<template>
  <el-menu
    mode="horizontal"
    background-color="#545c64"
    text-color="#fff"
    active-text-color="#fff"
  >
    <el-menu-item index="1"></el-menu-item>
    <el-sub-menu index="2">
      <template #title>文件</template>
      <el-menu-item index="2-1" @click="importImg">导入图片<input type="file" id="imageInput" style="display:none;" accept="image/*"></el-menu-item>
      <el-menu-item index="2-2" @click="exportSvg">导出svg</el-menu-item>
      <el-menu-item index="2-3" @click="exportPng">导出图片</el-menu-item>
    </el-sub-menu>
    <el-sub-menu index="3">
      <template #title>编辑</template>
      <el-menu-item index="3-1" @click="copy">复制(ctrl+c)</el-menu-item>
      <el-menu-item index="3-2" @click="paste">粘贴(ctrl+v)</el-menu-item>
      <el-menu-item index="3-3" @click="toBack">置底</el-menu-item>
      <el-menu-item index="3-4" @click="toFront">置顶</el-menu-item>
      <hr style="margin: 5px 0;color: #fff;">
      <el-menu-item index="3-5" @click="deleteObj">删除(delete)</el-menu-item>
      <el-menu-item index="3-6" @click="clear">清空</el-menu-item>
    </el-sub-menu>
  </el-menu>

  <div style="width: 100%;height: calc(100vh - 60px);">
    <el-menu
      :default-active="currentSelectIndex"
      collapse="false"
      background-color="#545c64"
      text-color="#fff"
      active-text-color="#ffd04b"
      style="height: 100%;float: left;width: 70px;font-size: 80px;"
      @select="handleSelect"
    >
      <el-menu-item index="1">
        <el-icon style="font-size: 60px;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path fill="currentColor" d="M17.147,20.757l-2.941,1.501l-3.677-6.005l-4.411,3.003V1.241l12.5,12.01l-4.412,1.501   L17.147,20.757z"></path>
          </svg>
        </el-icon>
      </el-menu-item>
      <el-menu-item index="2">
        <el-icon style="font-size: 60px;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path d="M 3 1 L 26 24 L 24 26 L 1 3 L 3 1 Z" fill="currentColor"></path>
          </svg>
        </el-icon>
      </el-menu-item>
      <el-menu-item index="3">
        <el-icon style="font-size: 60px;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path fill="currentColor" d="M19.616,9.216L6.647,21.567l-5.531,1.285l-0.1-0.094l1.449-5.269L15.438,5.204   c0.231-0.062,0.788-0.219,1.579-0.062L3.255,18.243l-0.394,1.381l1.58,1.504l1.481-0.375l0.66-0.598l0.065-1.408l-1.053-1.004   L18.203,5.736c0.196,0.157,0.196,0.157,0.396,0.376C20.476,7.869,19.616,9.216,19.616,9.216z M22.87,4.9   c-0.002,0.774-0.358,1.561-1.013,2.185l-1.217,1.16c0,0,0.921-1.348-0.989-3.103c-1.679-1.599-3.259-0.91-3.259-0.91l1.284-1.223   c1.154-1.126,3.161-1.126,4.278-0.062c0.622,0.549,0.913,1.239,0.915,1.938V4.9z"></path>
          </svg>
        </el-icon>
      </el-menu-item>
      <el-menu-item index="4">
        <el-icon style="font-size: 60px;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <rect x="0" y="0" width="24" height="24" r="0" rx="0" ry="0" fill="currentColor" stroke="currentColor" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect>
          </svg>
        </el-icon>
      </el-menu-item>
      <el-menu-item index="5">
        <el-icon style="font-size: 60px;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <ellipse cx="12" cy="12" rx="11" ry="8" fill="currentColor" stroke="currentColor" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></ellipse>
          </svg>
        </el-icon>
      </el-menu-item>
      <el-menu-item index="6">
        <el-icon style="font-size: 60px;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path fill="currentColor" d="M7.283,25.258v-1.741h0.539c1.133,0,1.879-0.204,2.224-0.64c0.345-0.422,0.525-1.157,0.525-2.191V4.355H8.733c-1.105,0-1.906,0.123-2.417,0.367C5.791,4.967,5.362,5.443,5.017,6.151C4.658,6.873,4.451,7.73,4.381,8.709H2.613V2.613h21.774v6.097H22.48c-0.359-1.701-0.87-2.858-1.52-3.457s-1.686-0.898-3.108-0.898h-1.976v16.331c0,1.062,0.165,1.81,0.525,2.218c0.358,0.409,1.104,0.613,2.236,0.613h0.595v1.741H7.283z"></path>
          </svg>
        </el-icon>
      </el-menu-item>
    </el-menu>
    <div class="main-div">
      <input type="text" id="inputBox" style="width:100px;height:30px;opacity:0;position:absolute;left:70px;top:60px">
      <div class="diagram-div" id="diagramDiv"></div>
    </div>
    <div class="property">
      <el-form :model="propertyForm" label-width="80" style="padding: 5px;max-width:240px;">
        <el-form-item label="宽度">
          <el-input-number v-model="propertyForm.width" :min="1" :max="1000" @change="handleWidth" />
        </el-form-item>
        <el-form-item label="高度">
          <el-input-number v-model="propertyForm.height" :min="1" :max="1000" @change="handleHeight" />
        </el-form-item>
        <el-form-item label="圆角">
          <el-input-number v-model="propertyForm.radius" :min="0" :max="100" @change="handleRadius" />
        </el-form-item>
        <el-form-item label="横向半径">
          <el-input-number v-model="propertyForm.hRadius" :min="1" :max="1000" @change="handleHRadius" />
        </el-form-item>
        <el-form-item label="竖向半径">
          <el-input-number v-model="propertyForm.vRadius" :min="1" :max="1000" @change="handleVRadius" />
        </el-form-item>
        <el-form-item label="旋转角度">
          <el-input-number v-model="propertyForm.rotate" @change="handleRotate" />
        </el-form-item>
        <el-form-item label="填充">
          <el-color-picker v-model="propertyForm.fill" @change="handleFill" />
        </el-form-item>
        <el-form-item label="透明度">
          <el-input-number v-model="propertyForm.fillOpacity" :min="0" :max="1" :step="0.1" @change="handleFillOpacity" />
        </el-form-item>
        <el-form-item label="描边">
          <el-color-picker v-model="propertyForm.stroke" @change="handleStroke" />
        </el-form-item>
        <el-form-item label="描边宽度">
          <el-input-number v-model="propertyForm.strokeWidth" :min="1" :max="50" @change="handleStrokeWidth" />
        </el-form-item>
        <el-form-item label="字体大小">
          <el-input-number v-model="propertyForm.fontSize" :min="1" :max="80" @change="handleFontSize" />
        </el-form-item>
        <el-form-item label="x轴">
          <el-input-number v-model="propertyForm.x" @change="handlePositionX" />
        </el-form-item>
        <el-form-item label="y轴">
          <el-input-number v-model="propertyForm.y" @change="handlePositionY" />
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script setup lang="ts">
defineOptions({
  name: "Dashboard",
  inheritAttrs: false,
});

import { Icon } from '@iconify/vue';
import { useUserStore } from "@/store/modules/user";
import router from "@/router";
import Raphael from "raphael";
const userStore = useUserStore();
const route = useRoute();

// 当前选择的功能
const currentSelectIndex = ref("1");
const handleSelect = (index) =>{
  currentSelectIndex.value = index;
  if (currentObj != null && currentObj.type == "text" && currentObj.attr("text") == ""){
    resizeSet.hide();
  }
  textCursor.hide();
  textCursor.data("status", "hide");
  if (textCursorInterval){
    clearInterval(textCursorInterval);
    textCursorInterval = undefined;
  }
}

let width = null;
let height = null;
let diagram = null;
let paper = null;
let mainSet = null;
let mainArr = [];
let resizeSet = null;
let currentObj = null; // 当前组件
let objCenterX = 0;
let objCenterY = 0;
let copyObj = null; // 复制的组件
let mouseMoveAttrs = { // 画布鼠标移动相关属性
  isDrawing: false,
  startX: null, 
  startY: null,
  currentX: null, 
  currentY: null,
  serialId: null,
  pathStr: "",
};
let inputBox = null; // text隐藏输入框

let undos = []; // 已执行命令集合
let redos = []; // 待执行命令集合

// 定义缩放旋转按钮
let nResize, eResize, sResize, wResize, neResize, nwResize, seResize, swResize;
let resizeRect; // 缩放框
let neRotateRect, seRotateRect, swRotateRect, nwRotateRect;
let textCursor;
let textCursorInterval;
// paper屏幕边距
const leftMargin = 410;
const topMargin = 50
const objMaxsize = 1000; // 组件尺寸最大值

// 属性相关
const showProperty = ref(false);
const propertyForm = reactive({
  width: 100,
  height: 100,
  radius: 0,
  hRadius: 50,
  vRadius: 50,
  rotate: 0,
  strokeWidth: 1,
  stroke: "#000",
  strokeOpacity: 1,
  fill: "#fff",
  fillOpacity: 1,
  text: "",
  fontSize: 24,
  x: 0,
  y: 0,
})
function handleWidth(value, oldValue){
  if (currentObj){
    if (currentObj.type == "rect" || currentObj.type == "image"){
      currentObj.attr("width", value);
      resizeRect.attr("width", value + 4);
      setResizeBtnLocation(currentObj.data("rotate"));
      propertyForm.x = currentObj.getBBox().x + currentObj.getBBox().width / 2;
      undos.push({ command: "WidthCommand", obj: currentObj, dWidth: value - oldValue, dHeight: 0, dx: 0, dy: 0 });
    }
    else if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleHeight(value, oldValue){
  if (currentObj){
    if (currentObj.type == "rect" || currentObj.type == "image"){
      currentObj.attr("height", value);
      resizeRect.attr("height", value + 4);
      setResizeBtnLocation(currentObj.data("rotate"));
      propertyForm.y = currentObj.getBBox().y + currentObj.getBBox().height / 2;
      undos.push({ command: "HeightCommand", obj: currentObj, dWidth: 0, dHeight: value - oldValue, dx: 0, dy: 0 });
    }
    else if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleRadius(value, oldValue){
  if (currentObj){
    if (currentObj.type == "rect"){
      currentObj.attr("r", value);
      undos.push({ command: "RadiusCommand", obj: currentObj, oldValue: oldValue, value: value});
    }
    else if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleHRadius(value, oldValue){
  if (currentObj){
    if (currentObj.type == "ellipse"){
      currentObj.attr("rx", value);
      resizeRect.attr("x", currentObj.getBBox(true).x - 2);
      resizeRect.attr("y", currentObj.getBBox(true).y - 2);
      resizeRect.attr("width", currentObj.getBBox(true).width + 4);
      resizeRect.attr("height", currentObj.getBBox(true).height + 4);
      setResizeBtnLocation(currentObj.data("rotate"));
      undos.push({ command: "HRadiusCommand", obj: currentObj, oldValue: oldValue, value: value});
    }
    else if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleVRadius(value, oldValue){
  if (currentObj){
    if (currentObj.type == "ellipse"){
      currentObj.attr("ry", value);
      resizeRect.attr("x", currentObj.getBBox(true).x - 2);
      resizeRect.attr("y", currentObj.getBBox(true).y - 2);
      resizeRect.attr("width", currentObj.getBBox(true).width + 4);
      resizeRect.attr("height", currentObj.getBBox(true).height + 4);
      setResizeBtnLocation(currentObj.data("rotate"));
      undos.push({ command: "VRadiusCommand", obj: currentObj, oldValue: oldValue, value: value});
    }
    else if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleRotate(value, oldValue){
  if (currentObj){
    resizeRect.rotate(value - oldValue);
    if (currentObj.type == "text"){
      let transformStr = resizeRect.matrix.toTransformString() + currentObj.data("scaleStr");
      currentObj = currentObj.transform(transformStr);
    }
    else{
      currentObj.rotate(value - oldValue);
    }
    currentObj.data("rotate", value);
    setResizeBtnLocation(value);
    undos.push({ command: "RotateObjectCommand", obj: currentObj, oldValue: oldValue, value: value });
    if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleStrokeWidth(value, oldValue){
  if (currentObj){
    undos.push({ command: "StrokeWidthCommand", obj: currentObj, oldValue: oldValue, value: value });
    currentObj.attr("stroke-width", value);
    if (currentObj.type == "text"){
      resizeRect.attr("width", currentObj.getBBox().width + 24);
      currentObj.data("resizeRectWidth", currentObj.getBBox().width + 24);
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
    else{
      resizeRect.attr("x", currentObj.getBBox(true).x - 2);
      resizeRect.attr("y", currentObj.getBBox(true).y - 2);
      resizeRect.attr("width", currentObj.getBBox(true).width + 4);
      resizeRect.attr("height", currentObj.getBBox(true).height + 4);
    }
    setResizeBtnLocation(currentObj.data("rotate"));
  }
}
function handleStroke(value){
  if (currentObj){
    let oldValue = currentObj.attr("stroke");
    undos.push({ command: "StrokeCommand", obj: currentObj, oldValue: oldValue, value: value });
    currentObj.attr("stroke", value);
    if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleFill(value){
  if (currentObj){
    let oldValue = currentObj.attr("fill");
    undos.push({ command: "FillCommand", obj: currentObj, oldValue: oldValue, value: value });
    currentObj.attr("fill", value);
    if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleFillOpacity(value, oldValue){
  if (currentObj){
    undos.push({ command: "FillOpacityCommand", obj: currentObj, oldValue: oldValue, value: value });
    currentObj.attr("fill-opacity", value);
    if (currentObj.type == "text"){
      setTimeout(() => {
        inputBox.focus();
      }, 100)
    }
  }
}
function handleFontSize(value, oldValue){
  if (currentObj && currentObj.type == "text"){
    undos.push({ command: "FontSizeCommand", obj: currentObj, oldValue: oldValue, value: value });
    currentObj.attr("font-size", value);
    resizeRect.attr("y", resizeRect.attr("y") - (value - oldValue));
    resizeRect.attr("width", resizeRect.attr("width") + (value - oldValue) * 2);
    resizeRect.attr("height", resizeRect.attr("height") + (value - oldValue) * 2);
    currentObj.data("resizeRectX", resizeRect.attr("x"));
    currentObj.data("resizeRectY", resizeRect.attr("y"));
    currentObj.data("resizeRectWidth", resizeRect.attr("width"));
    currentObj.data("resizeRectHeight", resizeRect.attr("height"));
    currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
    resizeRect.transform(resizeRect.matrix.toTransformString());
    setResizeBtnLocation(currentObj.data("rotate"));
    // 光标位置
    textCursor.show();
    textCursor.data("status", "show");
    textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
    textCursor.attr("y", resizeRect.getBBox(true).y + 2);
    textCursor.attr("height", resizeRect.getBBox(true).height - 4);
    textCursor.transform(resizeRect.matrix.toTransformString());
    if (!textCursorInterval) {
      textCursorInterval = setInterval(textCursorEvent, 500);
    }
    propertyForm.x = resizeRect.getBBox(true).x + resizeRect.getBBox(true).width / 2;
    propertyForm.y = resizeRect.getBBox(true).y + resizeRect.getBBox(true).height / 2;
    setTimeout(() => {
      inputBox.focus();
    }, 100)
  }
}
function handlePositionX(value, oldValue){
  handlePositionChange(value - oldValue, 0);
}
function handlePositionY(value, oldValue){
  handlePositionChange(0, value - oldValue);
}
function handlePositionChange(dx, dy){
  if (currentObj){
    currentObj.transform("t," + dx + "," + dy + currentObj.matrix.toTransformString());
    if (currentObj.type == "text"){
      resizeRect.transform("t," + dx + "," + dy + resizeRect.matrix.toTransformString());
      currentObj.data("resizeRectX", resizeRect.attr("x"));
      currentObj.data("resizeRectY", resizeRect.attr("y"));
      currentObj.data("resizeRectWidth", resizeRect.attr("width"));
      currentObj.data("resizeRectHeight", resizeRect.attr("height"));
      currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
      // 光标位置
      textCursor.show();
      textCursor.data("status", "show");
      textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
      textCursor.attr("y", resizeRect.getBBox(true).y + 2);
      textCursor.attr("height", resizeRect.getBBox(true).height - 4);
      textCursor.transform(resizeRect.matrix.toTransformString());
      if (!textCursorInterval) {
        textCursorInterval = setInterval(textCursorEvent, 500);
      }
      setTimeout(() => {
        inputBox.focus();
        inputBox.setSelectionRange(inputBox.value.length, inputBox.value.length);
      }, 10)
    }
    else{
      resizeRect.attr("x", currentObj.getBBox(true).x - 2);
      resizeRect.attr("y", currentObj.getBBox(true).y - 2);
      resizeRect.attr("width", currentObj.getBBox(true).width + 4);
      resizeRect.attr("height", currentObj.getBBox(true).height + 4);
      resizeRect.transform(currentObj.matrix.toTransformString());
    }
    setResizeBtnLocation(currentObj.data("rotate"));
    undos.push({ command: "MoveObjectCommand", obj: currentObj, dx: dx, dy: dy });
  }
}

//缩放相关参数
//coef:每次放大、缩小的增量;
//zoom:目前的大小与原来大小的比例;
//(x,y):目前缩放图的左上角坐标;
//w,h:以(x,y)为原点取得宽度和高度;
const scale = {coef: 0.05, zoom: 1, x: 0, y: 0, w: 0, h: 0};

// 初始化
onMounted(() => {
  diagram = document.getElementById("diagramDiv");

  width = diagram.clientWidth;
  height = diagram.clientHeight;
  let startX = 0;
  let startY = 0;
  paper = new Raphael("diagramDiv", width, height);
  paper.canvas.id = "paper";
  mainSet = paper.set();

  neRotateRect = drawRotateRect(paper);
  seRotateRect = drawRotateRect(paper);
  swRotateRect = drawRotateRect(paper);
  nwRotateRect = drawRotateRect(paper);

  resizeRect = paper.rect(0, 0, 1, 1);
  resizeRect.attr({ "stroke-width": 1, "stroke": "blue"})
  resizeRect.hide();

  resizeSet = paper.set();
  // 定义缩放旋转按钮
  nResize = drawScaleBtn(paper, "n", "yellow");
  eResize = drawScaleBtn(paper, "e", "green");
  sResize = drawScaleBtn(paper, "s", "red");
  wResize = drawScaleBtn(paper, "w", "blue");
  neResize = drawScaleBtn(paper, "ne", "yellow");
  nwResize = drawScaleBtn(paper, "nw", "green");
  seResize = drawScaleBtn(paper, "se", "red");
  swResize = drawScaleBtn(paper, "sw", "blue");
  resizeSet.push(neRotateRect, seRotateRect, swRotateRect, nwRotateRect, nResize, eResize, sResize, wResize, neResize, nwResize, seResize, swResize, resizeRect);
  textCursor = paper.rect(0, 0, 1, 28);
  textCursor.hide();
  textCursor.data("status", "hide");
  
  diagram.addEventListener('mouseover', diagramMouseOver);
  diagram.addEventListener('mousedown', diagramMouseDown);
  diagram.addEventListener('mousemove', diagramMouseMove);
  diagram.addEventListener('mouseup', diagramMouseUp);

  inputBox = document.getElementById('inputBox');
  inputBox.addEventListener('input', function(event) {
    if (currentObj && currentObj.type == "text"){
      let oldValue = currentObj.attr("text");
      currentObj.attr("text", inputBox.value);
      resizeRect.attr("width", currentObj.getBBox().width + 24);
      currentObj.data("resizeRectX", resizeRect.attr("x"));
      currentObj.data("resizeRectY", resizeRect.attr("y"));
      currentObj.data("resizeRectWidth", resizeRect.attr("width"));
      currentObj.data("resizeRectHeight", resizeRect.attr("height"));
      currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
      setResizeBtnLocation(currentObj.data("rotate") ? currentObj.data("rotate") : 0);
      textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
      textCursor.attr("y", resizeRect.getBBox(true).y + 2);
      textCursor.attr("height", resizeRect.getBBox(true).height - 4);
      textCursor.transform(resizeRect.matrix.toTransformString());
      setProperty();
      undos.push({ command: "TextCommand", obj: currentObj, oldValue: oldValue, value: inputBox.value });
    }
  });

  // 键盘事件
  document.addEventListener('keydown', function(event) {
    switch(event.keyCode || event.key) {
      case 46: // 删除
      case 'Delete':
        deleteObj();
        break;
      case 37: // 左键
      case 'ArrowLeft':
        handlePositionChange(-1, 0);
        break;
      case 38: // 上键
      case 'ArrowUp':
        handlePositionChange(0, -1);
        break;
      case 39: // 右键
      case 'ArrowRight':
        handlePositionChange(1, 0);
        break;
      case 40: // 下键
      case 'ArrowDown':
        handlePositionChange(0, 1);
        break;
      default:
        break;
    }

    if (event.key === "z" && event.ctrlKey){
      event.preventDefault();
      undo();
    }
    if (event.key === "y" && event.ctrlKey){
      event.preventDefault();
      redo();
    }
  });

  // 监听剪贴板的复制事件
  document.addEventListener('copy', function(event) {
    copy();
    event.preventDefault(); // 阻止默认的复制行为
  });

  // 监听粘贴事件
  document.addEventListener('paste', function(event) {
    paste();
    event.preventDefault(); // 阻止默认的粘贴行为
  });

  // 放大缩小
  //一些全局参数
  const maxSize = 3; //允许放大的最大倍数
  const minSize = 0.5; //允许缩小的最大倍数

  scale.w = width;
  scale.h = height;

  //更新Scale
  function updateScale(x, y, w, h) {
      scale.w = w;
      scale.h = h;
      scale.x = x;
      scale.y = y;
  }

  //获取操作前的viewbox中心点
  function getLastCenterPoint() {
      var centerPoint = {};
      centerPoint.x = scale.x + scale.w / 2;
      centerPoint.y = scale.y + scale.h / 2;
      return centerPoint;
  }

  /**
   *鼠标滚轮缩放
    *
    */
  function onMouseWheeling(e) {
      var dtl;
      if (e.wheelDelta) { //chrome
        dtl = e.wheelDelta;
      } else if (e.detail) {//firefox or others
        dtl = -e.detail;
      }
      if (dtl < 0) {
        //缩小,
        if (scale.zoom < minSize) {
          return;
        }
        scale.zoom -= scale.coef;
      } else {
        //放大
        if (scale.zoom > maxSize) {
          return;
        }
        scale.zoom += scale.coef;
      }
      //计算新的视图参数
      var w = width / scale.zoom;
      var h = height / scale.zoom;
      var lastCenterPoint = getLastCenterPoint();
      var x = lastCenterPoint.x - w / 2;
      var y = lastCenterPoint.y - h / 2;
      updateScale(x, y, w, h);
      paper.setViewBox(x, y, w, h, false);
  }

  if (document.addEventListener) {
      document.addEventListener('DOMMouseScroll', onMouseWheeling, false);
      window.onmousewheel = document.onmousewheel = onMouseWheeling;//IE/Opera/Chrome/Safari
  } else {
      alert("鼠标滚轮监听事件绑定失败");
  }

  // 图片选择事件
  document.getElementById('imageInput').addEventListener('change', function(event) {
    const file = event.target.files[0]; // 获取选择的文件
    if (file) {
      let url = window.URL || window.webkitURL;
      let img = new Image();              //手动创建一个Image对象
      img.src = url.createObjectURL(this.files[0]);//创建Image的对象的url
      convertToBase64(url.createObjectURL(this.files[0]), (base64) => {
          drawImage(paper, 20, 20, base64, img.width, img.height);
      });
    }
  });
});

function convertToBase64(url, callback) {
    const img = new Image();
    img.crossOrigin = 'Anonymous'; // 如果图片跨域，需要设置此属性
    img.onload = () => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        canvas.height = img.height;
        canvas.width = img.width;
        ctx.drawImage(img, 0, 0);
        const dataUrl = canvas.toDataURL('image/svg+xml');
        callback(dataUrl);
    };
    img.src = url;
}

/*
  * 画布mouseover事件
*/
function diagramMouseOver() {
  if (currentSelectIndex.value == "1"){
    this.style.cursor = 'default';
  }
  else if (currentSelectIndex.value == "3"){
    this.style.cursor = "url(/images/pen.png) 5 15,default";
  }
  else if (currentSelectIndex.value == "6"){
    this.style.cursor = "text";
  }
  else{
    this.style.cursor = 'crosshair';
  }
}

/*
  * 画布mousedown事件
*/
function diagramMouseDown(e){
  mouseMoveAttrs.isDrawing = true;
  mouseMoveAttrs.startX = e.offsetX / scale.zoom + scale.x;
  mouseMoveAttrs.startY = e.offsetY / scale.zoom + scale.y;
  mouseMoveAttrs.currentX = null;
  mouseMoveAttrs.currentY = null;
  mouseMoveAttrs.serialId = new Date().getTime();
  mouseMoveAttrs.pathStr = "M" +mouseMoveAttrs.startX + " " + mouseMoveAttrs.startY;
}

/*
  * 画布mousemove事件
*/
function diagramMouseMove(e){
  if (!mouseMoveAttrs.isDrawing) return;
  
  mouseMoveAttrs.currentX = e.offsetX / scale.zoom + scale.x;
  mouseMoveAttrs.currentY = e.offsetY / scale.zoom + scale.y;
  
  for(let i = 0; i < mainSet.length; i++){
    let obj = mainSet[i];
    if (obj.data("serialId") == mouseMoveAttrs.serialId ){
      obj.remove();
    }
  }
  switch(currentSelectIndex.value){
    case "1":
      break;
    case "2":
      let path = drawPath(paper, mouseMoveAttrs.startX,
        mouseMoveAttrs.startY,
        mouseMoveAttrs.currentX,
        mouseMoveAttrs.currentY, 1, "black", 1);
      currentObj = path;
      mainSet.push(currentObj);
      setProperty();
      break;
    case "3":
      mouseMoveAttrs.pathStr += "L" + mouseMoveAttrs.currentX + " " + mouseMoveAttrs.currentY;
      let line = drawLine(paper, mouseMoveAttrs.pathStr, 1, "#000", "#fff", 1);
      currentObj = line;
      mainSet.push(currentObj);
      setProperty();
      break;
    case "4":
      let rect = drawRect(paper, Math.min(mouseMoveAttrs.startX, mouseMoveAttrs.currentX),
        Math.min(mouseMoveAttrs.startY, mouseMoveAttrs.currentY),
        Math.abs(mouseMoveAttrs.currentX - mouseMoveAttrs.startX),
        Math.abs(mouseMoveAttrs.currentY - mouseMoveAttrs.startY), 1, "#fff", "#000", 1);
      currentObj = rect;
      mainSet.push(rect); 
      setProperty();
      break;
    case "5":
      let ellipse = drawEllipse(paper, (mouseMoveAttrs.startX + mouseMoveAttrs.currentX) / 2,
        (mouseMoveAttrs.startY + mouseMoveAttrs.currentY) / 2,
        Math.abs(mouseMoveAttrs.currentX - mouseMoveAttrs.startX),
        Math.abs(mouseMoveAttrs.currentY- mouseMoveAttrs.startY), 1, "#fff", "#000", 1);
      currentObj = ellipse;
      mainSet.push(currentObj); 
      setProperty();
      break;
    default:
      break;
  }
}

/*
  * 画布mouseup事件
*/
function diagramMouseUp(e){
  mouseMoveAttrs.isDrawing = false;
  if (currentSelectIndex.value == "1") {
    
  }
  else if (currentSelectIndex.value == "6"){ // 文字
    let text = drawText(paper, e.offsetX / scale.zoom + scale.x, e.offsetY / scale.zoom + scale.y, "", 24, 0, "black", "black", 1);
    currentObj = text;
    currentObj.data("scaleStr", "");
    currentObj.data("resizeRectX", e.offsetX / scale.zoom + scale.x - 12);
    currentObj.data("resizeRectY", e.offsetY / scale.zoom + scale.y - 16);
    currentObj.data("resizeRectWidth", 24);
    currentObj.data("resizeRectHeight", 32);
    mainSet.push(currentObj);
    textCursor.attr("x", 0);
    textCursor.attr("y", 0);
    textCursor.attr("height", 28);
    textCursor.show();
    textCursor.data("status", "show");
    textCursor.transform("t" + (e.offsetX / scale.zoom + scale.x) + "," + (e.offsetY / scale.zoom + scale.y - 14) + "r0");
    if (!textCursorInterval) {
      textCursorInterval = setInterval(textCursorEvent, 500);
    }
    resizeRect.transform("t0,0r0");
    resizeRect.attr("x", e.offsetX / scale.zoom + scale.x - 12);
    resizeRect.attr("y", e.offsetY / scale.zoom + scale.y - 16);
    resizeRect.attr("width", 24);
    resizeRect.attr("height", 32);
    resizeRect.data("scaleX", 1);
    resizeRect.data("scaleY", 1);
    resizeRect.data("scaleCX", 0);
    resizeRect.data("scaleCY", 0);
    resizeRect.show();
    setResizeBtnLocation();
    resizeRect.toFront();
    resizeSet.toFront();
    inputBox.value = "";
    inputBox.focus();
    setProperty();
    propertyForm.x = e.offsetX / scale.zoom + scale.x;
    propertyForm.y = e.offsetY / scale.zoom + scale.y;
    mainArr.push(currentObj);
    undos.push({ command: "AddObjectCommand", obj: currentObj });
  }
  else{
    resizeRect.transform("t0,0r0");
    resizeRect.attr("x", currentObj.getBBox().x - 2);
    resizeRect.attr("y", currentObj.getBBox().y - 2);
    resizeRect.attr("width", currentObj.getBBox().width + 4);
    resizeRect.attr("height", currentObj.getBBox().height + 4);
    resizeRect.show();
    setResizeBtnLocation();
    resizeRect.toFront();
    resizeSet.toFront();
    mainArr.push(currentObj);
    undos.push({ command: "AddObjectCommand", obj: currentObj });
  }
};

/*
  * 光标闪烁事件
*/
function textCursorEvent(){
  if (textCursor.data("status") == "hide"){
    textCursor.show();
    textCursor.data("status", "show");
  }
  else{
    textCursor.hide();
    textCursor.data("status", "hide");
  }
}

/*
  * 设置组件属性值
*/
function setProperty(){
  if (currentObj){
    propertyForm.width = 100;
    propertyForm.height = 100;
    propertyForm.radius = 0;
    propertyForm.hRadius = 50;
    propertyForm.vRadius = 50;
    propertyForm.rotate = currentObj.data("rotate") ? currentObj.data("rotate") : 0;
    propertyForm.strokeWidth = currentObj.attr("stroke-width");
    propertyForm.stroke = currentObj.attr("stroke");
    propertyForm.fill = currentObj.attr("fill");
    propertyForm.fillOpacity = currentObj.attr("fill-opacity");
    propertyForm.text = "";
    propertyForm.fontSize = 24;
    propertyForm.x = currentObj.getBBox().x + currentObj.getBBox().width / 2;
    propertyForm.y = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    switch (currentObj.type){
      case "rect":
      case "image":
        propertyForm.width = currentObj.attr("width");
        propertyForm.height = currentObj.attr("height");
        propertyForm.radius = currentObj.attr("r");
      break;
      case "ellipse":
        propertyForm.hRadius = currentObj.attr("rx");
        propertyForm.vRadius = currentObj.attr("ry");
      break;
      case "text":
        propertyForm.fontSize = currentObj.attr("font-size");
        propertyForm.x = resizeRect.getBBox(true).x + resizeRect.getBBox(true).width / 2;
        propertyForm.y = resizeRect.getBBox(true).y + resizeRect.getBBox(true).height / 2;
      break;
      default:
      break;
    }
  }
  else{
    propertyForm.width = 100;
    propertyForm.height = 100;
    propertyForm.radius = 0;
    propertyForm.hRadius = 50;
    propertyForm.vRadius = 50;
    propertyForm.rotate = 0;
    propertyForm.strokeWidth = 1;
    propertyForm.stroke = "#000";
    propertyForm.fill = "#fff";
    propertyForm.fillOpacity = 1;
    propertyForm.text = "";
    propertyForm.fontSize = 24;
    propertyForm.x = 0;
    propertyForm.y = 0;
  }
}

/*
  * 复制
*/
function copy(){
  copyObj = currentObj;
}

/*
  * 粘贴
*/
function paste(){
  // 处理粘贴的内容
  if (copyObj != null){
    switch (copyObj.type){
      case "rect":
      case "image":
        currentObj = drawRect(paper, copyObj.attr("x"), copyObj.attr("y"), copyObj.attr("width"), copyObj.attr("height"), 
        copyObj.attr("stroke-width"), copyObj.attr("fill"), copyObj.attr("stroke"), copyObj.attr("fill-opacity"), copyObj.data("rotate"));
        currentObj.transform("t100,100" + copyObj.matrix.toTransformString());
        resizeRect.transform("t100,100" + copyObj.matrix.toTransformString());
        setResizeBtnLocation(copyObj.data("rotate"));
        setProperty();
        mainSet.push(currentObj);
        mainArr.push(currentObj);
        undos.push({ command: "CopyObjectCommand", obj: currentObj });
      break;
      case "ellipse":
        currentObj = drawEllipse(paper, copyObj.attr("cx"), copyObj.attr("cy"), copyObj.attr("rx"), copyObj.attr("ry"), 
          copyObj.attr("stroke-width"), copyObj.attr("fill"), copyObj.attr("stroke"), copyObj.attr("fill-opacity"), copyObj.data("rotate"));
        currentObj.transform("t100,100" + copyObj.matrix.toTransformString());
        resizeRect.transform("t100,100" + copyObj.matrix.toTransformString());
        setResizeBtnLocation(copyObj.data("rotate"));
        setProperty();
        mainSet.push(currentObj);
        mainArr.push(currentObj);
        undos.push({ command: "CopyObjectCommand", obj: currentObj });
      break;
      case "path":
        if (copyObj.attr("path").length == 2){ // 直线
          let path = copyObj.attr("path");
          currentObj = drawPath(paper, path[0][1], path[0][2], path[1][1], path[1][2], 
          copyObj.attr("stroke-width"), copyObj.attr("stroke"), copyObj.data("rotate"));
          currentObj.transform("t100,100" + copyObj.matrix.toTransformString());
          resizeRect.transform("t100,100" + copyObj.matrix.toTransformString());
          setResizeBtnLocation(copyObj.data("rotate"));
          setProperty();
          mainSet.push(currentObj);
          mainArr.push(currentObj);
          undos.push({ command: "CopyObjectCommand", obj: currentObj });
        }
        else{ // 曲线
          let path = copyObj.attr("path");
          currentObj = drawLine(paper, path, copyObj.attr("stroke-width"), copyObj.attr("stroke"), copyObj.attr("fill"), 
          copyObj.attr("fill-opacity"), copyObj.data("rotate"));
          currentObj.transform("t100,100" + copyObj.matrix.toTransformString());
          resizeRect.transform("t100,100" + copyObj.matrix.toTransformString());
          setResizeBtnLocation(copyObj.data("rotate"));
          setProperty();
          mainSet.push(currentObj);
          mainArr.push(currentObj);
          undos.push({ command: "CopyObjectCommand", obj: currentObj });
        }
      break;
      case "text":
        if (copyObj.attr("text")){
          currentObj = drawText(paper, copyObj.attr("x"), copyObj.attr("y"), copyObj.attr("text"), copyObj.attr("font-size"), 
            copyObj.attr("stroke-width"), copyObj.attr("fill"), copyObj.attr("stroke"), copyObj.attr("fill-opacity"), copyObj.data("rotate"));
          currentObj.transform("t100,100" + copyObj.matrix.toTransformString());
          resizeRect.transform("t100,100" + resizeRect.matrix.toTransformString());
          currentObj.data("scaleStr", copyObj.data("scaleStr"));
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          // 光标位置
          textCursor.show();
          textCursor.data("status", "show");
          textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
          textCursor.attr("y", resizeRect.getBBox(true).y + 2);
          textCursor.attr("height", resizeRect.getBBox(true).height - 4);
          textCursor.transform(resizeRect.matrix.toTransformString());
          if (!textCursorInterval) {
            textCursorInterval = setInterval(textCursorEvent, 500);
          }
          setResizeBtnLocation(copyObj.data("rotate"));
          setProperty();
          mainSet.push(currentObj);
          mainArr.push(currentObj);
          undos.push({ command: "CopyObjectCommand", obj: currentObj });
        }
      break;
      default:
      break;
    }
  }
}

/*
  * 撤销
*/
function undo(){
  if (undos.length > 0){
    let cmd = undos.pop();
    switch(cmd.command){
      case "CopyObjectCommand":
        cmd.obj.hide();
        currentObj = null;
        resizeRect.hide();
        resizeSet.hide();
        inputBox.blur();
        // 光标隐藏
        textCursor.hide();
        textCursor.data("status", "hide");
        if (textCursorInterval){
          clearInterval(textCursorInterval);
          textCursorInterval = undefined;
        }
        // 设置属性值
        setProperty();
      break;
      case "DeleteObjectCommand":
        cmd.obj.show();
        currentObj = cmd.obj;
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "AddObjectCommand":
        cmd.obj.hide();
        currentObj = null;
        resizeRect.hide();
        resizeSet.hide();
        inputBox.blur();
        // 光标隐藏
        textCursor.hide();
        textCursor.data("status", "hide");
        if (textCursorInterval){
          clearInterval(textCursorInterval);
          textCursorInterval = undefined;
        }
        // 设置属性值
        setProperty();
      break;
      case "MoveObjectCommand":
        currentObj = cmd.obj;
        if (currentObj.type == "text"){
          resizeRect.attr("x", currentObj.data("resizeRectX"));
          resizeRect.attr("y", currentObj.data("resizeRectY"));
          resizeRect.attr("width", currentObj.data("resizeRectWidth"));
          resizeRect.attr("height", currentObj.data("resizeRectHeight"));
          resizeRect.show();
          resizeRect.transform(currentObj.data("resizeRectTransform"));
          currentObj.transform("t" + (-cmd.dx) + "," + (-cmd.dy) + currentObj.matrix.toTransformString());
          resizeRect.transform("t," + (-cmd.dx) + "," + (-cmd.dy) + resizeRect.matrix.toTransformString());
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          // 光标位置
          textCursor.show();
          textCursor.data("status", "show");
          textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
          textCursor.attr("y", resizeRect.getBBox(true).y + 2);
          textCursor.attr("height", resizeRect.getBBox(true).height - 4);
          textCursor.transform(resizeRect.matrix.toTransformString());
          if (!textCursorInterval) {
            textCursorInterval = setInterval(textCursorEvent, 500);
          }
          setTimeout(() => {
            inputBox.focus();
            inputBox.setSelectionRange(inputBox.value.length, inputBox.value.length);
          }, 10)
        }
        else{
          currentObj.transform("t" + (-cmd.dx) + "," + (-cmd.dy) + currentObj.matrix.toTransformString());
          resizeRect.show();
          resizeRect.attr("x", currentObj.getBBox(true).x - 2);
          resizeRect.attr("y", currentObj.getBBox(true).y - 2);
          resizeRect.attr("width", currentObj.getBBox(true).width + 4);
          resizeRect.attr("height", currentObj.getBBox(true).height + 4);
          resizeRect.transform(currentObj.matrix.toTransformString());
          // 光标隐藏
          textCursor.hide();
          textCursor.data("status", "hide");
          if (textCursorInterval){
            clearInterval(textCursorInterval);
            textCursorInterval = undefined;
          }
        }
        setResizeBtnLocation(currentObj.data("rotate"));
        // 设置属性值
        setProperty();
      break;
      case "ResizeObjectCommand":
        currentObj = cmd.obj;
        let direction = cmd.direction;
        switch(cmd.direction){
          case "n":
            if (cmd.dy > cmd.startHeight){
              direction = "s";
            }
            break;
          case "e":
            if (-cmd.dx > cmd.startWidth){
              direction = "w";
            }
            break;
          case "s":
            if (-cmd.dy > cmd.startHeight){
              direction = "n";
            }
            break;
          case "w":
            if (cmd.dx > cmd.startWidth){
              direction = "e";
            }
            break;
          case "ne":
            if (-cmd.dx > cmd.startWidth / 2 && cmd.dy > cmd.startHeight / 2){
              direction = "sw";
            }
            else if (-cmd.dx > cmd.startWidth / 2){
              direction = "nw";
            }
            else if (cmd.dy > cmd.startHeight / 2){
              direction = "se";
            }
            break;
          case "se":
            if (-cmd.dx > cmd.startWidth / 2 && -cmd.dy > cmd.startHeight / 2){
              direction = "nw";
            }
            else if (-cmd.dx > cmd.startWidth / 2){
              direction = "sw";
            }
            else if (-cmd.dy > cmd.startHeight / 2){
              direction = "ne";
            }
            break;
          case "sw":
            if (cmd.dx > cmd.startWidth / 2 && -cmd.dy > cmd.startHeight / 2){
              direction = "ne";
            }
            else if (cmd.dx > cmd.startWidth / 2){
              direction = "se";
            }
            else if (-cmd.dy > cmd.startHeight / 2){
              direction = "nw";
            }
            break;
          case "nw":
            if (cmd.dx > cmd.startWidth / 2 && cmd.dy > cmd.startHeight / 2){
              direction = "se";
            }
            else if (cmd.dx > cmd.startWidth / 2){
              direction = "ne";
            }
            else if (cmd.dy > cmd.startHeight / 2){
              direction = "sw";
            }
            break;
        }
        resizeBtnMove(direction, -cmd.dx, -cmd.dy, cmd.currentX, cmd.currentY, cmd.currentWidth, cmd.currentHeight, cmd.currentPath, cmd.sourcePath);
        currentObj.data("scaleStr", "s" + resizeRect.data("scaleX") + "," + resizeRect.data("scaleY") + "," + resizeRect.data("scaleCX") + "," + resizeRect.data("scaleCY") + currentObj.data("scaleStr"));
        resizeRect.show();
        setResizeBtnLocation(currentObj.data("rotate"));
        // 设置属性值
        setProperty();
      break;
      case "WidthCommand":
        currentObj = cmd.obj;
        currentObj.attr("width", currentObj.attr("width") - cmd.dWidth);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "HeightCommand":
        currentObj = cmd.obj;
        currentObj.attr("height", currentObj.attr("height") - cmd.dHeight);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "RadiusCommand":
        currentObj = cmd.obj;
        currentObj.attr("r", cmd.oldValue);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "HRadiusCommand":
        currentObj = cmd.obj;
        currentObj.attr("rx", cmd.oldValue);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "VRadiusCommand":
        currentObj = cmd.obj;
        currentObj.attr("ry", cmd.oldValue);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "RotateObjectCommand":
        currentObj = cmd.obj;
        resizeRect.rotate(cmd.oldValue - cmd.value);
        if (currentObj.type == "text"){
          let transformStr = resizeRect.matrix.toTransformString() + currentObj.data("scaleStr");
          currentObj = currentObj.transform(transformStr);
        }
        else{
          currentObj.rotate(cmd.oldValue - cmd.value);
        }
        currentObj.data("rotate", cmd.oldValue);
        currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "StrokeWidthCommand":
        currentObj = cmd.obj;
        currentObj.attr("stroke-width", cmd.oldValue);
        if (currentObj.type == "text"){
          currentObj.data("resizeRectWidth", currentObj.getBBox().width + 24);
        }
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "StrokeCommand":
        currentObj = cmd.obj;
        currentObj.attr("stroke", cmd.oldValue);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "FillCommand":
        currentObj = cmd.obj;
        currentObj.attr("fill", cmd.oldValue);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "FillOpacityCommand":
        currentObj = cmd.obj;
        currentObj.attr("fill-opacity", cmd.oldValue);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "FontSizeCommand":
        currentObj = cmd.obj;
        currentObj.attr("font-size", cmd.oldValue);
        resizeRect.attr("y", resizeRect.attr("y") + (cmd.value - cmd.oldValue));
        resizeRect.attr("width", resizeRect.attr("width") - (cmd.value - cmd.oldValue) * 2);
        resizeRect.attr("height", resizeRect.attr("height") - (cmd.value - cmd.oldValue) * 2);
        currentObj.data("resizeRectX", resizeRect.attr("x"));
        currentObj.data("resizeRectY", resizeRect.attr("y"));
        currentObj.data("resizeRectWidth", resizeRect.attr("width"));
        currentObj.data("resizeRectHeight", resizeRect.attr("height"));
        currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
        resizeRect.transform(resizeRect.matrix.toTransformString());
        setResizeBtnLocation(currentObj.data("rotate"));
        // 光标位置
        textCursor.show();
        textCursor.data("status", "show");
        textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
        textCursor.attr("y", resizeRect.getBBox(true).y + 2);
        textCursor.attr("height", resizeRect.getBBox(true).height - 4);
        textCursor.transform(resizeRect.matrix.toTransformString());
        if (!textCursorInterval) {
          textCursorInterval = setInterval(textCursorEvent, 500);
        }
        // 设置属性值
        setProperty();
      break;
      case "TextCommand":
        currentObj = cmd.obj;
        currentObj.attr("text", cmd.oldValue);
        resizeRect.attr("width", currentObj.getBBox().width + 24);
        currentObj.data("resizeRectX", resizeRect.attr("x"));
        currentObj.data("resizeRectY", resizeRect.attr("y"));
        currentObj.data("resizeRectWidth", resizeRect.attr("width"));
        currentObj.data("resizeRectHeight", resizeRect.attr("height"));
        currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
        setResizeBtnLocation(currentObj.data("rotate") ? currentObj.data("rotate") : 0);
        textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
        textCursor.attr("y", resizeRect.getBBox(true).y + 2);
        textCursor.attr("height", resizeRect.getBBox(true).height - 4);
        textCursor.transform(resizeRect.matrix.toTransformString());
        // 设置属性值
        setProperty();
      break;
    }
    redos.push(cmd);
  }
}

/*
  * 重做
*/
function redo(){
  if (redos.length > 0){
    let cmd = redos.pop();
    switch(cmd.command){
      case "CopyObjectCommand":
        cmd.obj.show();
        currentObj = cmd.obj;
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "DeleteObjectCommand":
        cmd.obj.hide();
        currentObj = null;
        resizeRect.hide();
        resizeSet.hide();
        // 光标隐藏
        textCursor.hide();
        textCursor.data("status", "hide");
        if (textCursorInterval){
          clearInterval(textCursorInterval);
          textCursorInterval = undefined;
        }
        // 设置属性值
        setProperty();
      break;
      case "AddObjectCommand":
        cmd.obj.show();
        currentObj = cmd.obj;
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "MoveObjectCommand":
        currentObj = cmd.obj;
        if (currentObj.type == "text"){
          resizeRect.attr("x", currentObj.data("resizeRectX"));
          resizeRect.attr("y", currentObj.data("resizeRectY"));
          resizeRect.attr("width", currentObj.data("resizeRectWidth"));
          resizeRect.attr("height", currentObj.data("resizeRectHeight"));
          resizeRect.show();
          resizeRect.transform(currentObj.data("resizeRectTransform"));
          currentObj.transform("t" + (cmd.dx) + "," + (cmd.dy) + currentObj.matrix.toTransformString());
          resizeRect.transform("t," + (cmd.dx) + "," + (cmd.dy) + resizeRect.matrix.toTransformString());
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          // 光标位置
          textCursor.show();
          textCursor.data("status", "show");
          textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
          textCursor.attr("y", resizeRect.getBBox(true).y + 2);
          textCursor.attr("height", resizeRect.getBBox(true).height - 4);
          textCursor.transform(resizeRect.matrix.toTransformString());
          if (!textCursorInterval) {
            textCursorInterval = setInterval(textCursorEvent, 500);
          }
          setTimeout(() => {
            inputBox.focus();
            inputBox.setSelectionRange(inputBox.value.length, inputBox.value.length);
          }, 10)
        }
        else{
          currentObj.transform("t" + (cmd.dx) + "," + (cmd.dy) + currentObj.matrix.toTransformString());
          resizeRect.show();
          resizeRect.attr("x", currentObj.getBBox(true).x - 2);
          resizeRect.attr("y", currentObj.getBBox(true).y - 2);
          resizeRect.attr("width", currentObj.getBBox(true).width + 4);
          resizeRect.attr("height", currentObj.getBBox(true).height + 4);
          resizeRect.transform(currentObj.matrix.toTransformString());
          // 光标隐藏
          textCursor.hide();
          textCursor.data("status", "hide");
          if (textCursorInterval){
            clearInterval(textCursorInterval);
            textCursorInterval = undefined;
          }
        }
        setResizeBtnLocation(currentObj.data("rotate"));
        // 设置属性值
        setProperty();
      break;
      case "ResizeObjectCommand":
        currentObj = cmd.obj;
        resizeBtnMove(cmd.direction, cmd.dx, cmd.dy, cmd.startX, cmd.startY, cmd.startWidth, cmd.startHeight, cmd.sourcePath, cmd.currentPath);
        currentObj.data("scaleStr", "s" + resizeRect.data("scaleX") + "," + resizeRect.data("scaleY") + "," + resizeRect.data("scaleCX") + "," + resizeRect.data("scaleCY") + currentObj.data("scaleStr"));
        setResizeBtnLocation(currentObj.data("rotate"));
        // 设置属性值
        setProperty();
      break;
      case "WidthCommand":
        currentObj = cmd.obj;
        currentObj.attr("width", currentObj.attr("width") + cmd.dWidth);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "HeightCommand":
        currentObj = cmd.obj;
        currentObj.attr("height", currentObj.attr("height") + cmd.dHeight);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "RadiusCommand":
        currentObj = cmd.obj;
        currentObj.attr("r", cmd.value);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "HRadiusCommand":
        currentObj = cmd.obj;
        currentObj.attr("rx", cmd.value);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "VRadiusCommand":
        currentObj = cmd.obj;
        currentObj.attr("ry", cmd.value);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "RotateObjectCommand":
      currentObj = cmd.obj;
        resizeRect.rotate(cmd.value - cmd.oldValue);
        if (currentObj.type == "text"){
          let transformStr = resizeRect.matrix.toTransformString() + currentObj.data("scaleStr");
          currentObj = currentObj.transform(transformStr);
        }
        else{
          currentObj.rotate(cmd.value - cmd.oldValue);
        }
        currentObj.data("rotate", cmd.value);
        currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "StrokeWidthCommand":
        currentObj = cmd.obj;
        currentObj.attr("stroke-width", cmd.value);
        if (currentObj.type == "text"){
          currentObj.data("resizeRectWidth", currentObj.getBBox().width + 24);
        }
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "StrokeCommand":
        currentObj = cmd.obj;
        currentObj.attr("stroke", cmd.value);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "FillCommand":
        currentObj = cmd.obj;
        currentObj.attr("fill", cmd.value);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "FillOpacityCommand":
        currentObj = cmd.obj;
        currentObj.attr("fill-opacity", cmd.value);
        showResize(currentObj);
        // 设置属性值
        setProperty();
      break;
      case "FontSizeCommand":
        currentObj = cmd.obj;
        currentObj.attr("font-size", cmd.value);
        resizeRect.attr("y", resizeRect.attr("y") - (cmd.value - cmd.oldValue));
        resizeRect.attr("width", resizeRect.attr("width") + (cmd.value - cmd.oldValue) * 2);
        resizeRect.attr("height", resizeRect.attr("height") + (cmd.value - cmd.oldValue) * 2);
        currentObj.data("resizeRectX", resizeRect.attr("x"));
        currentObj.data("resizeRectY", resizeRect.attr("y"));
        currentObj.data("resizeRectWidth", resizeRect.attr("width"));
        currentObj.data("resizeRectHeight", resizeRect.attr("height"));
        currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
        resizeRect.transform(resizeRect.matrix.toTransformString());
        setResizeBtnLocation(currentObj.data("rotate"));
        // 光标位置
        textCursor.show();
        textCursor.data("status", "show");
        textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
        textCursor.attr("y", resizeRect.getBBox(true).y + 2);
        textCursor.attr("height", resizeRect.getBBox(true).height - 4);
        textCursor.transform(resizeRect.matrix.toTransformString());
        if (!textCursorInterval) {
          textCursorInterval = setInterval(textCursorEvent, 500);
        }
        // 设置属性值
        setProperty();
      break;
      case "TextCommand":
        currentObj = cmd.obj;
        currentObj.attr("text", cmd.value);
        resizeRect.attr("width", currentObj.getBBox().width + 24);
        currentObj.data("resizeRectX", resizeRect.attr("x"));
        currentObj.data("resizeRectY", resizeRect.attr("y"));
        currentObj.data("resizeRectWidth", resizeRect.attr("width"));
        currentObj.data("resizeRectHeight", resizeRect.attr("height"));
        currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
        setResizeBtnLocation(currentObj.data("rotate") ? currentObj.data("rotate") : 0);
        textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
        textCursor.attr("y", resizeRect.getBBox(true).y + 2);
        textCursor.attr("height", resizeRect.getBBox(true).height - 4);
        textCursor.transform(resizeRect.matrix.toTransformString());
        // 设置属性值
        setProperty();
      break;
    }
    undos.push(cmd);
  }
}

/*
  * 显示形变按钮
*/
function showResize(obj){
  if (obj.type == "text"){
    resizeRect.attr("x", obj.data("resizeRectX"));
    resizeRect.attr("y", obj.data("resizeRectY"));
    resizeRect.attr("width", obj.data("resizeRectWidth"));
    resizeRect.attr("height", obj.data("resizeRectHeight"));
    resizeRect.show();
    resizeRect.transform(obj.data("resizeRectTransform"));
    setResizeBtnLocation(obj.data("rotate"));
    inputBox.focus();
    // 光标位置
    textCursor.show();
    textCursor.data("status", "show");
    textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
    textCursor.attr("y", resizeRect.getBBox(true).y + 2);
    textCursor.attr("height", resizeRect.getBBox(true).height - 4);
    textCursor.transform(resizeRect.matrix.toTransformString());
    if (!textCursorInterval) {
      textCursorInterval = setInterval(textCursorEvent, 500);
    }
  }
  else{
    resizeRect.attr("x", obj.getBBox(true).x - 2);
    resizeRect.attr("y", obj.getBBox(true).y - 2);
    resizeRect.attr("width", obj.getBBox(true).width + 4);
    resizeRect.attr("height", obj.getBBox(true).height + 4);
    resizeRect.show();
    resizeRect.transform(obj.matrix.toTransformString());
    setResizeBtnLocation(obj.data("rotate"));
    // 光标隐藏
    textCursor.hide();
    textCursor.data("status", "hide");
    if (textCursorInterval){
      clearInterval(textCursorInterval);
      textCursorInterval = undefined;
    }
  }
}

/*
  * 画矩形
  * params:画布,矩形横坐标,矩形纵坐标,矩形宽,矩形高,矩形边框,填充颜色,边框颜色,透明度,旋转角度
*/
function drawRect(paper, startX, startY, w, h, s, fill, stroke, fillOpacity, rotate){
  let rect = paper.rect(
    startX,
    startY,
    w,
    h
  )
  .data("serialId", mouseMoveAttrs.serialId)
  .data("rotate", 0)
  .attr({ "fill": fill, "stroke": stroke, 'stroke-width': s, "fill-opacity": fillOpacity })
  .hover(function(){
    if (currentSelectIndex.value == "1"){
      this.attr('cursor', 'move');
    }
  },function(){})
  .mousedown(function(){
    if (currentSelectIndex.value == "1"){
      currentObj = rect;
      resizeRect.attr("x", rect.getBBox(true).x - 2);
      resizeRect.attr("y", rect.getBBox(true).y - 2);
      resizeRect.attr("width", rect.getBBox(true).width + 4);
      resizeRect.attr("height", rect.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(rect.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(rect.data("rotate"));
      // 光标隐藏
      textCursor.hide();
      textCursor.data("status", "hide");
      if (textCursorInterval){
        clearInterval(textCursorInterval);
        textCursorInterval = undefined;
      }
      // 设置属性值
      setProperty();
    }
  },function(){})
  .drag(rectMove, rectStartMove, rectEndMove);

  if (rotate){
    rect.rotate(rotate)
    rect.data("rotate", rotate);
  }

  function rectStartMove(dx, dy){
    //为元素自定义属性并赋值
    this.tempx = 0;
    this.tempy = 0;
  }

  function rectMove(dx,dy,x,y){
    if (currentSelectIndex.value == "1"){
      this.transform("t" + (dx - this.tempx) + "," + (dy - this.tempy) + this.matrix.toTransformString());
      // this.translate(dx - this.tempx, dy - this.tempy);
      this.tempx = dx;
      this.tempy = dy;
      resizeRect.attr("x", rect.getBBox(true).x - 2);
      resizeRect.attr("y", rect.getBBox(true).y - 2);
      resizeRect.attr("width", rect.getBBox(true).width + 4);
      resizeRect.attr("height", rect.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(rect.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(rect.data("rotate"));
      // 设置属性x/y值
      propertyForm.x = currentObj.getBBox().x + currentObj.getBBox().width / 2;
      propertyForm.y = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    }
  }

  function rectEndMove(){
    undos.push({ command: "MoveObjectCommand", obj: rect, dx: this.tempx, dy: this.tempy });
  }

  return rect;
}

/*
  * 画椭圆
  * params:画布,椭圆横坐标,椭圆纵坐标,椭圆宽度,椭圆高度,边框,填充颜色,边框颜色,透明度,旋转角度
*/
function drawEllipse(paper, startX, startY, w, h, s, fill, stroke, fillOpacity, rotate){
  //创建椭圆
  let ellipse = paper.ellipse(startX, startY, w, h)
  .attr({'fill': fill, 'stroke': stroke, 'stroke-width': s, "fill-opacity": fillOpacity})
  .data("serialId", mouseMoveAttrs.serialId)
  .data("rotate", 0)
  .hover(function(){
    if (currentSelectIndex.value == "1"){
      this.attr('cursor', 'move');
    }
  },function(){})
  .mousedown(function(){
    if (currentSelectIndex.value == "1"){
      currentObj = ellipse;
      resizeRect.attr("x", ellipse.getBBox(true).x - 2);
      resizeRect.attr("y", ellipse.getBBox(true).y - 2);
      resizeRect.attr("width", ellipse.getBBox(true).width + 4);
      resizeRect.attr("height", ellipse.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(ellipse.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(ellipse.data("rotate"));
      // 光标隐藏
      textCursor.hide();
      textCursor.data("status", "hide");
      if (textCursorInterval){
        clearInterval(textCursorInterval);
        textCursorInterval = undefined;
      }
      // 设置属性值
      setProperty();
    }
  },function(){})
  .drag(ellipseMove, ellipseStartMove, ellipseEndMove);

  if (rotate){
    ellipse.rotate(rotate)
    ellipse.data("rotate", rotate);
  }

  function ellipseStartMove(dx, dy){
    this.tempx = 0;
    this.tempy = 0;    
  }

  function ellipseMove(dx, dy, x, y){
    if (currentSelectIndex.value == "1"){
      this.transform("t" + (dx - this.tempx) + "," + (dy - this.tempy) + this.matrix.toTransformString());
      // this.translate(dx - this.tempx, dy - this.tempy);
      this.tempx = dx;
      this.tempy = dy;
      resizeRect.attr("x", ellipse.getBBox(true).x - 2);
      resizeRect.attr("y", ellipse.getBBox(true).y - 2);
      resizeRect.attr("width", ellipse.getBBox(true).width + 4);
      resizeRect.attr("height", ellipse.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(ellipse.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(ellipse.data("rotate"));
      // 设置属性x/y值
      propertyForm.x = currentObj.getBBox().x + currentObj.getBBox().width / 2;
      propertyForm.y = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    }
  }

  function ellipseEndMove(){
    undos.push({ command: "MoveObjectCommand", obj: ellipse, dx: this.tempx, dy: this.tempy });
  }
  return ellipse;
}

/*
  * 画直线
  * params:画布,起点横坐标,起点纵坐标,终点横坐标,终点横坐标,线粗细,线颜色,旋转角度
*/
function drawPath(paper, startX, startY, endX, endY, s, stroke, rotate){
  let path = paper.path("M" + startX + " " + startY + "L" + endX + " " + endY)
  .attr({'stroke': stroke, 'stroke-width': s})
  .data("serialId", mouseMoveAttrs.serialId)
  .data("rotate", 0)
  .hover(function(){
    if (currentSelectIndex.value == "1"){
      this.attr('cursor', 'move');
    }
  },function(){})
  .mousedown(function(){
    if (currentSelectIndex.value == "1"){
      currentObj = path;
      resizeRect.attr("x", path.getBBox(true).x - 2);
      resizeRect.attr("y", path.getBBox(true).y - 2);
      resizeRect.attr("width", path.getBBox(true).width + 4);
      resizeRect.attr("height", path.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(path.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(path.data("rotate"));
      // 光标隐藏
      textCursor.hide();
      textCursor.data("status", "hide");
      if (textCursorInterval){
        clearInterval(textCursorInterval);
        textCursorInterval = undefined;
      }
      // 设置属性值
      setProperty();
    }
  },function(){})
  .drag(lineMove, lineStartMove, lineEndMove);

  if (rotate){
    path.rotate(rotate);
    path.data("rotate", rotate);
  }

  function lineStartMove(dx, dy){
    this.tempx = 0;
    this.tempy = 0; 
  }

  function lineMove(dx,dy,x,y){
    if (currentSelectIndex.value == "1"){
      this.transform("t" + (dx - this.tempx) + "," + (dy - this.tempy) + this.matrix.toTransformString());
      // this.translate(dx - this.tempx, dy - this.tempy);
      this.tempx = dx;
      this.tempy = dy;
      resizeRect.attr("x", this.getBBox(true).x - 2);
      resizeRect.attr("y", this.getBBox(true).y - 2);
      resizeRect.attr("width", this.getBBox(true).width + 4);
      resizeRect.attr("height", this.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(this.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(this.data("rotate"));
      // 设置属性x/y值
      propertyForm.x = currentObj.getBBox().x + currentObj.getBBox().width / 2;
      propertyForm.y = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    }
  }

  function lineEndMove(){
    undos.push({ command: "MoveObjectCommand", obj: line, dx: this.tempx, dy: this.tempy });
  }
  return path;
}

/*
  * 画不规则线
  * params:画布,线路经,线粗细,线颜色,填充颜色,透明度,旋转角度
*/
function drawLine(paper, pathStr, s, stroke, fill, fillOpacity, rotate){
  let line = paper.path(pathStr)
  .attr({'stroke': stroke, 'stroke-width': s, "fill": fill, "fill-opacity": fillOpacity})
  .data("serialId", mouseMoveAttrs.serialId)
  .data("rotate", 0)
  .hover(function(){
    if (currentSelectIndex.value == "1"){
      this.attr('cursor', 'move');
    }
  },function(){})
  .mousedown(function(){
    if (currentSelectIndex.value == "1"){
      currentObj = line;
      resizeRect.attr("x", line.getBBox(true).x - 2);
      resizeRect.attr("y", line.getBBox(true).y - 2);
      resizeRect.attr("width", line.getBBox(true).width + 4);
      resizeRect.attr("height", line.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(line.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(line.data("rotate"));
      // 光标隐藏
      textCursor.hide();
      textCursor.data("status", "hide");
      if (textCursorInterval){
        clearInterval(textCursorInterval);
        textCursorInterval = undefined;
      }
      // 设置属性值
      setProperty();
    }
  },function(){})
  .drag(lineMove, lineStartMove, lineEndMove);

  if (rotate){
    line.rotate(rotate);
    line.data("rotate", rotate);
  }

  function lineStartMove(dx, dy){
    this.tempx = 0;
    this.tempy = 0; 
  }

  function lineMove(dx,dy,x,y){
    if (currentSelectIndex.value == "1"){
      this.transform("t" + (dx - this.tempx) + "," + (dy - this.tempy) + this.matrix.toTransformString());
      // this.translate(dx - this.tempx, dy - this.tempy);
      this.tempx = dx;
      this.tempy = dy;
      resizeRect.attr("x", this.getBBox(true).x - 2);
      resizeRect.attr("y", this.getBBox(true).y - 2);
      resizeRect.attr("width", this.getBBox(true).width + 4);
      resizeRect.attr("height", this.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(this.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(this.data("rotate"));
      // 设置属性x/y值
      propertyForm.x = currentObj.getBBox().x + currentObj.getBBox().width / 2;
      propertyForm.y = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    }
  }

  function lineEndMove(){
    undos.push({ command: "MoveObjectCommand", obj: line, dx: this.tempx, dy: this.tempy });
  }
  return line;
}

/*
  * 画文字
  * params:画布,中心点横坐标,中心点纵坐标,文字内容,文字大小,线宽,填充颜色,边框颜色,透明度,旋转角度,数据源,字段
*/
function drawText(paper, startX, startY, content, fontSize, strokeWidth, fill, stroke, fillOpacity, rotate, dataSource, column){
  let text = paper.text(startX, startY, content)
  .attr({ "font-size": fontSize, "text-anchor": "start", 'fill': fill, 'stroke': stroke, 'stroke-width': strokeWidth, "fill-opacity": fillOpacity })
  .data("rotate", 0)
  .hover(function(){
    if (currentSelectIndex.value == "1"){
      this.attr('cursor', 'move');
    }
  },function(){})
  .mousedown(function(e){
    if (currentSelectIndex.value == "1"){
      currentObj = text;
      resizeRect.attr("x", text.data("resizeRectX"));
      resizeRect.attr("y", text.data("resizeRectY"));
      resizeRect.attr("width", text.data("resizeRectWidth"));
      resizeRect.attr("height", text.data("resizeRectHeight"));
      resizeRect.show();
      resizeRect.transform(text.data("resizeRectTransform"));
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(text.data("rotate"));
      // 光标位置
      textCursor.show();
      textCursor.data("status", "show");
      textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
      textCursor.attr("y", resizeRect.getBBox(true).y + 2);
      textCursor.attr("height", resizeRect.getBBox(true).height - 4);
      textCursor.transform(resizeRect.matrix.toTransformString());
      if (!textCursorInterval) {
        textCursorInterval = setInterval(textCursorEvent, 500);
      }
      // 设置属性值
      setProperty();
    }
  },function(){})
  .mouseup(function(e){
    if (currentSelectIndex.value == "1"){
      inputBox.value = currentObj.attr("text");
      inputBox.focus();
    }
  },function(){})
  .drag(textMove, textStartMove, textEndMove);

  if (rotate){
    text.rotate(rotate);
    text.data("rotate", rotate);
  }

  function textStartMove(dx, dy){
    this.tempx = 0;
    this.tempy = 0; 
  }

  function textMove(dx,dy,x,y){
    if (currentSelectIndex.value == "1"){
      this.transform("t" + (dx - this.tempx) + "," + (dy - this.tempy) + this.matrix.toTransformString());
      resizeRect.transform("t" + (dx - this.tempx) + "," + (dy - this.tempy) + resizeRect.matrix.toTransformString());
      // this.translate(dx - this.tempx, dy - this.tempy);
      this.tempx = dx;
      this.tempy = dy;
      resizeRect.show();
      setResizeBtnLocation(text.data("rotate"));
      resizeRect.toFront();
      resizeSet.toFront();
      this.data("resizeRectX", resizeRect.attr("x"));
      this.data("resizeRectY", resizeRect.attr("y"));
      this.data("resizeRectWidth", resizeRect.attr("width"));
      this.data("resizeRectHeight", resizeRect.attr("height"));
      this.data("resizeRectTransform", resizeRect.matrix.toTransformString());
      // 光标位置
      textCursor.show();
      textCursor.data("status", "show");
      textCursor.attr("x", resizeRect.getBBox(true).x + resizeRect.getBBox(true).width - 12);
      textCursor.attr("y", resizeRect.getBBox(true).y + 2);
      textCursor.attr("height", resizeRect.getBBox(true).height - 4);
      textCursor.transform(resizeRect.matrix.toTransformString());
      if (!textCursorInterval) {
        textCursorInterval = setInterval(textCursorEvent, 500);
      }
      // 设置属性x/y值
      propertyForm.x = currentObj.getBBox().x + currentObj.getBBox().width / 2;
      propertyForm.y = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    }
  }

  function textEndMove(){
    undos.push({ command: "MoveObjectCommand", obj: text, dx: this.tempx, dy: this.tempy });
  }
  return text;
}

/*
  * 画图片
  * params:画布,中心点横坐标,中心点纵坐标,宽度,高度,旋转角度
*/
function drawImage(paper, startX, startY, url, w, h, rotate){
  let image = paper.image(url, startX, startY, w, h)
  .data("rotate", 0)
  .hover(function(){
    if (currentSelectIndex.value == "1"){
      this.attr('cursor', 'move');
    }
  },function(){})
  .mousedown(function(){
    if (currentSelectIndex.value == "1"){
      currentObj = image;
      resizeRect.attr("x", image.getBBox(true).x - 2);
      resizeRect.attr("y", image.getBBox(true).y - 2);
      resizeRect.attr("width", image.getBBox(true).width + 4);
      resizeRect.attr("height", image.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(image.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(image.data("rotate"));
      // 光标隐藏
      textCursor.hide();
      textCursor.data("status", "hide");
      if (textCursorInterval){
        clearInterval(textCursorInterval);
        textCursorInterval = undefined;
      }
      // 设置属性值
      setProperty();
    }
  },function(){})
  .drag(imageMove, imageStartMove, imageEndMove);

  if (rotate){
    image.rotate(rotate);
    image.data("rotate", rotate);
  }

  function imageStartMove(dx, dy){
    this.tempx = 0;
    this.tempy = 0; 
  }

  function imageMove(dx,dy,x,y){
    if (currentSelectIndex.value == "1"){
      this.transform("t" + (dx - this.tempx) + "," + (dy - this.tempy) + this.matrix.toTransformString());
      this.tempx = dx;
      this.tempy = dy;
      resizeRect.attr("x", image.getBBox(true).x - 2);
      resizeRect.attr("y", image.getBBox(true).y - 2);
      resizeRect.attr("width", image.getBBox(true).width + 4);
      resizeRect.attr("height", image.getBBox(true).height + 4);
      resizeRect.show();
      resizeRect.transform(image.matrix.toTransformString());
      resizeRect.toFront();
      resizeSet.toFront();
      setResizeBtnLocation(image.data("rotate"));
      // 设置属性x/y值
      propertyForm.x = currentObj.getBBox().x + currentObj.getBBox().width / 2;
      propertyForm.y = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    }
  }

  function imageEndMove(){
    undos.push({ command: "MoveObjectCommand", obj: image, dx: this.tempx, dy: this.tempy });
  }

  return image;
}

/*
  * 定义缩放按钮
  * params:画布,缩放方向
*/
function drawScaleBtn(paper, direction, color){
  let outer = paper.rect(0, 0, 8, 8)
    .drag(outerMove, outerStartMove, outerEndMove)
    .attr({fill: color})
    .hover(function(){
      setResizeBtnCursor(outer, direction)
    },function(){});

  let outerX = 0;
  let outerY = 0;
  let startW = 0; // 形变框初始宽度
  let startH = 0; // 形变框初始高度
  let sourcePath = "";
  let ddx = 0;
  let ddy = 0;

  function outerStartMove(){
    diagram.removeEventListener("mouseover", diagramMouseOver);
    diagram.removeEventListener("mousedown", diagramMouseDown);
    diagram.removeEventListener("mousemove", diagramMouseMove);
    diagram.removeEventListener("mouseup", diagramMouseUp);

    outerX = resizeRect.attr("x");
    outerY = resizeRect.attr("y");
    startW = resizeRect.attr("width");
    startH = resizeRect.attr("height");
    sourcePath = currentObj.attr("path");
    objCenterX = currentObj.getBBox().x + currentObj.getBBox().width / 2 ;
    objCenterY = currentObj.getBBox().y + currentObj.getBBox().height / 2;
  }

  function outerMove(dx, dy, x, y){
    ddx = dx;
    ddy = dy;
    resizeBtnMove(direction, dx, dy, outerX, outerY, startW, startH, sourcePath);
    setResizeBtnLocation(currentObj.data("rotate") ? currentObj.data("rotate") : 0);
    setProperty();
  }

  function outerEndMove(e){
    currentObj.data("scaleStr", "s" + resizeRect.data("scaleX") + "," + resizeRect.data("scaleY") + "," + resizeRect.data("scaleCX") + "," + resizeRect.data("scaleCY") + currentObj.data("scaleStr"));
    diagram.style.cursor = 'default';
    diagram.addEventListener("mouseover", diagramMouseOver);
    diagram.addEventListener("mousedown", diagramMouseDown);
    diagram.addEventListener("mousemove", diagramMouseMove);
    diagram.addEventListener("mouseup", diagramMouseUp);
    // undos.push({ command: "ResizeObjectCommand", obj: currentObj, dWidth: resizeRect.attr("width") - startW, 
    //   dHeight: resizeRect.attr("height") - startH, dx: resizeRect.attr("x") - outerX, dy: resizeRect.attr("y") - outerY });
    undos.push({ command: "ResizeObjectCommand", obj: currentObj, direction: direction, dx: ddx, dy: ddy, startX: outerX, 
      startY: outerY, startWidth: startW, startHeight: startH, currentX: resizeRect.attr("x"), currentY: resizeRect.attr("y"), 
      currentWidth: resizeRect.attr("width"), currentHeight: resizeRect.attr("height"), sourcePath: sourcePath, currentPath: currentObj.attr("path")
    });
  }
  outer.hide();
  return outer;
}

/*
  * 缩放按钮鼠标悬停事件
  * params:缩放按钮,缩放方向
*/
function setResizeBtnCursor(outer, direction){
  if (currentObj.data("rotate") > -22.5 && currentObj.data("rotate") <= 22.5){
    outer.attr('cursor', direction + '-resize');
  }
  else if (currentObj.data("rotate") > 22.5 && currentObj.data("rotate") <= 67.5){
    switch (direction){
      case "n":
        outer.attr('cursor', 'ne-resize');
        break;
      case "e":
        outer.attr('cursor', 'se-resize');
        break;
      case "s":
        outer.attr('cursor', 'sw-resize');
        break;
      case "w":
        outer.attr('cursor', 'nw-resize');
      break;
      case "ne":
        outer.attr('cursor', 'e-resize');
        break;
      case "se":
        outer.attr('cursor', 's-resize');
        break;
      case "sw":
        outer.attr('cursor', 'w-resize');
        break;
      case "nw":
        outer.attr('cursor', 'n-resize');
        break;
    }
  }
  else if (currentObj.data("rotate") > 67.5 && currentObj.data("rotate") <= 112.5){
    switch (direction){
      case "n":
        outer.attr('cursor', 'e-resize');
        break;
      case "e":
        outer.attr('cursor', 's-resize');
        break;
      case "s":
        outer.attr('cursor', 'w-resize');
        break;
      case "w":
        outer.attr('cursor', 'n-resize');
      break;
      case "ne":
        outer.attr('cursor', 'se-resize');
        break;
      case "se":
        outer.attr('cursor', 'sw-resize');
        break;
      case "sw":
        outer.attr('cursor', 'nw-resize');
        break;
      case "nw":
        outer.attr('cursor', 'ne-resize');
        break;
    }
  }
  else if (currentObj.data("rotate") > 112.5 && currentObj.data("rotate") <= 157.5){
    switch (direction){
      case "n":
        outer.attr('cursor', 'se-resize');
        break;
      case "e":
        outer.attr('cursor', 'sw-resize');
        break;
      case "s":
        outer.attr('cursor', 'nw-resize');
        break;
      case "w":
        outer.attr('cursor', 'ne-resize');
      break;
      case "ne":
        outer.attr('cursor', 's-resize');
        break;
      case "se":
        outer.attr('cursor', 'w-resize');
        break;
      case "sw":
        outer.attr('cursor', 'n-resize');
        break;
      case "nw":
        outer.attr('cursor', 'e-resize');
        break;
    }
  }
  else if (currentObj.data("rotate") > 157.5 || currentObj.data("rotate") <= -157.5){
    switch (direction){
      case "n":
        outer.attr('cursor', 's-resize');
        break;
      case "e":
        outer.attr('cursor', 'w-resize');
        break;
      case "s":
        outer.attr('cursor', 'n-resize');
        break;
      case "w":
        outer.attr('cursor', 'e-resize');
      break;
      case "ne":
        outer.attr('cursor', 'sw-resize');
        break;
      case "se":
        outer.attr('cursor', 'nw-resize');
        break;
      case "sw":
        outer.attr('cursor', 'ne-resize');
        break;
      case "nw":
        outer.attr('cursor', 'se-resize');
        break;
    }
  }
  else if (currentObj.data("rotate") > -157.5 && currentObj.data("rotate") <= -112.5){
    switch (direction){
      case "n":
        outer.attr('cursor', 'sw-resize');
        break;
      case "e":
        outer.attr('cursor', 'nw-resize');
        break;
      case "s":
        outer.attr('cursor', 'ne-resize');
        break;
      case "w":
        outer.attr('cursor', 'se-resize');
      break;
      case "ne":
        outer.attr('cursor', 'w-resize');
        break;
      case "se":
        outer.attr('cursor', 'n-resize');
        break;
      case "sw":
        outer.attr('cursor', 'e-resize');
        break;
      case "nw":
        outer.attr('cursor', 's-resize');
        break;
    }
  }
  else if (currentObj.data("rotate") > -112.5 && currentObj.data("rotate") <= -67.5){
    switch (direction){
      case "n":
        outer.attr('cursor', 'w-resize');
        break;
      case "e":
        outer.attr('cursor', 'n-resize');
        break;
      case "s":
        outer.attr('cursor', 'e-resize');
        break;
      case "w":
        outer.attr('cursor', 's-resize');
      break;
      case "ne":
        outer.attr('cursor', 'nw-resize');
        break;
      case "se":
        outer.attr('cursor', 'ne-resize');
        break;
      case "sw":
        outer.attr('cursor', 'se-resize');
        break;
      case "nw":
        outer.attr('cursor', 'sw-resize');
        break;
    }
  }
  else if (currentObj.data("rotate") > -67.5 && currentObj.data("rotate") <= -22.5){
    switch (direction){
      case "n":
        outer.attr('cursor', 'nw-resize');
        break;
      case "e":
        outer.attr('cursor', 'ne-resize');
        break;
      case "s":
        outer.attr('cursor', 'se-resize');
        break;
      case "w":
        outer.attr('cursor', 'sw-resize');
      break;
      case "ne":
        outer.attr('cursor', 'n-resize');
        break;
      case "se":
        outer.attr('cursor', 'e-resize');
        break;
      case "sw":
        outer.attr('cursor', 's-resize');
        break;
      case "nw":
        outer.attr('cursor', 'w-resize');
        break;
    }
  }
}

/*
  * 缩放按钮拖动事件
  * params:缩放按钮,缩放方向
*/
function resizeBtnMove(direction, dx, dy, initX, initY, initWidth, initHeight, sourcePath, currentPath){
  let step = calcStep(direction, dx, dy);
  dx = step.dx;
  dy = step.dy;
  switch (direction){
    case "n":
      if (initHeight == 4 && currentObj.type == "path") return; // 横向直线，不做变化
      if (dy > initHeight){
        resizeRect.attr("y", initY + initHeight);
        resizeRect.attr("height", dy - initHeight);
      }
      else{
        resizeRect.attr("y", initY + dy);
        resizeRect.attr("height", initHeight - dy);
      }
      switch(currentObj.type){
        case "rect":
        case "image":
          currentObj.attr("y", resizeRect.attr("y") + 2);
          currentObj.attr("height", resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4);
          break;
        case "ellipse":
          currentObj.attr("cy", resizeRect.attr("y") + 2 + (resizeRect.attr("height") - 4) / 2);
          currentObj.attr("ry", (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          break;
        case "path":
          let newPathN = [];
          if (currentPath){
            newPathN = currentPath;
          }
          else{
            for (let i = 0; i < sourcePath.length; i++){
              let newY;
              if (dy > initHeight){
                newY = sourcePath[i][2] + (dy - 8) * (initHeight - 4 - (sourcePath[i][2] - (initY + 2))) / (initHeight - 4) + 4;
              }
              else{
                newY = sourcePath[i][2] + dy * (initHeight - 4 - (sourcePath[i][2] - (initY + 2))) / (initHeight - 4);
              }
              newPathN.push([sourcePath[i][0], sourcePath[i][1], newY]);
            }
          }
          currentObj.attr("path", newPathN);
          break;
        case "text":
          if (dy > initHeight){
            let transformStr = resizeRect.matrix.toTransformString() + "s1," + (- resizeRect.attr("height") / initHeight) + "," + (resizeRect.attr("x")) + "," + (resizeRect.attr("y")) + currentObj.data("scaleStr");
            currentObj.transform(transformStr);
            resizeRect.data("scaleX", 1);
            resizeRect.data("scaleY", (-resizeRect.attr("height") / initHeight));
            resizeRect.data("scaleCX", resizeRect.attr("x"));
            resizeRect.data("scaleCY", resizeRect.attr("y"));
          }
          else{
            let transformStr = resizeRect.matrix.toTransformString() + "s1," + (resizeRect.attr("height") / initHeight) + "," + (resizeRect.attr("x")) + "," + (resizeRect.attr("y") + resizeRect.attr("height")) + currentObj.data("scaleStr");
            currentObj.transform(transformStr);
            resizeRect.data("scaleX", 1);
            resizeRect.data("scaleY", (resizeRect.attr("height") / initHeight));
            resizeRect.data("scaleCX", resizeRect.attr("x"));
            resizeRect.data("scaleCY", resizeRect.attr("y") + resizeRect.attr("height"));
          }
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          break;
      }
      break;
    case "e":
      if (initWidth == 4 && currentObj.type == "path") return; // 竖向向直线，不做变化
      if (-dx > initWidth){
        resizeRect.attr("x", initX - (-dx - initWidth));
        resizeRect.attr("width", -dx - initWidth);
      }
      else{
        resizeRect.attr("x", initX);
        resizeRect.attr("width", initWidth + dx);
      }
      switch(currentObj.type){
        case "rect":
        case "image":
          currentObj.attr("x", resizeRect.attr("x") + 2);
          currentObj.attr("width", resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4);
          break;
        case "ellipse":
          currentObj.attr("cx", resizeRect.attr("x") + 2 + (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("rx", (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          break;
        case "path":
          let newPathE = [];
          if (currentPath){
            newPathE = currentPath;
          }
          else{
            for (let i = 0; i < sourcePath.length; i++){
              let newX;
              if (-dx > initWidth){
                newX = sourcePath[i][1] + (dx + 8) * (sourcePath[i][1] - (initX + 2)) / (initWidth - 4) - 4;
              }
              else{
                newX = sourcePath[i][1] + dx * (sourcePath[i][1] - (initX + 2)) / (initWidth - 4);
              }
              newPathE.push([sourcePath[i][0], newX, sourcePath[i][2]]);
            }
          }
          currentObj.attr("path", newPathE);
          break;
        case "text":
          if (-dx > initWidth){
            let transformStr = resizeRect.matrix.toTransformString() + "s" + (- resizeRect.attr("width") / initWidth) + ",1," + (resizeRect.attr("x") + resizeRect.attr("width")) + "," + (resizeRect.attr("y")) + currentObj.data("scaleStr");
            currentObj.transform(transformStr);
            resizeRect.data("scaleX", (- resizeRect.attr("width") / initWidth));
            resizeRect.data("scaleY", 1);
            resizeRect.data("scaleCX", resizeRect.attr("x") + resizeRect.attr("width"));
            resizeRect.data("scaleCY", resizeRect.attr("y"));
          }
          else{
            let transformStr = resizeRect.matrix.toTransformString() + "s" + (resizeRect.attr("width") / initWidth) + ",1," + (resizeRect.attr("x")) + "," + (resizeRect.attr("y")) + currentObj.data("scaleStr");
            currentObj.transform(transformStr);
            resizeRect.data("scaleX", (resizeRect.attr("width") / initWidth));
            resizeRect.data("scaleY", 1);
            resizeRect.data("scaleCX", resizeRect.attr("x"));
            resizeRect.data("scaleCY", resizeRect.attr("y"));
          }
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          break;
      }
      break;
    case "s":
      if (initHeight == 4 && currentObj.type == "path") return; // 横向直线，不做变化
      if (-dy > initHeight){
        resizeRect.attr("y", initY - (-dy - initHeight));
        resizeRect.attr("height", -dy - initHeight);
      }
      else{
        resizeRect.attr("y", initY);
        resizeRect.attr("height", initHeight + dy);
      }
      switch(currentObj.type){
        case "rect":
        case "image":
          currentObj.attr("y", resizeRect.attr("y") + 2);
          currentObj.attr("height", resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("height")- 4);
          break;
        case "ellipse":
          currentObj.attr("cy", resizeRect.attr("y") + 2 + (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          currentObj.attr("ry", (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          break;
        case "path":
          let newPathS = [];
          if (currentPath){
            newPathS = currentPath;
          }
          else{
            for (let i = 0; i < sourcePath.length; i++){
              let newY;
              if (dy > initHeight){
                newY = sourcePath[i][2] + (dy + 8) * (sourcePath[i][2] - (initY + 2)) / (initHeight - 4) - 4;
              }
              else{
                newY = sourcePath[i][2] + dy * (sourcePath[i][2] - (initY + 2)) / (initHeight - 4);
              }
              newPathS.push([sourcePath[i][0], sourcePath[i][1], newY]);
            }
          }
          currentObj.attr("path", newPathS);
          break;
        case "text":
          if (-dy > initHeight){
            let transformStr = resizeRect.matrix.toTransformString() + "s1," + (- resizeRect.attr("height") / initHeight) + "," + (resizeRect.attr("x")) + "," + (resizeRect.attr("y") + resizeRect.attr("height")) + currentObj.data("scaleStr");
            currentObj.transform(transformStr);
            resizeRect.data("scaleX", 1);
            resizeRect.data("scaleY", (-resizeRect.attr("height") / initHeight));
            resizeRect.data("scaleCX", resizeRect.attr("x"));
            resizeRect.data("scaleCY", resizeRect.attr("y") + resizeRect.attr("height"));
          }
          else{
            let transformStr = resizeRect.matrix.toTransformString() + "s1," + (resizeRect.attr("height") / initHeight) + "," + (resizeRect.attr("x")) + "," + (resizeRect.attr("y")) + currentObj.data("scaleStr");
            currentObj.transform(transformStr);
            resizeRect.data("scaleX", 1);
            resizeRect.data("scaleY", (resizeRect.attr("height") / initHeight));
            resizeRect.data("scaleCX", resizeRect.attr("x"));
            resizeRect.data("scaleCY", resizeRect.attr("y"));
          }
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          break;
      }
      break;
    case "w":
      if (initWidth == 4 && currentObj.type == "path") return; // 竖向向直线，不做变化
      if (dx > initWidth){
        resizeRect.attr("x", initX + initWidth);
        resizeRect.attr("width", dx - initWidth);
      }
      else{
        resizeRect.attr("x", initX + dx);
        resizeRect.attr("width", initWidth - dx);
      }
      switch(currentObj.type){
        case "rect":
        case "image":
          currentObj.attr("x", resizeRect.attr("x") + 2);
          currentObj.attr("width", resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4);
          break;
        case "ellipse":
          currentObj.attr("cx", resizeRect.attr("x") + 2 + (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("rx", (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          break;
        case "path":
          let newPathW = [];
          if (currentPath){
            newPathW = currentPath;
          }
          else{
            for (let i = 0; i < sourcePath.length; i++){
              let newX;
              if (dx > initWidth){
                newX = sourcePath[i][1] + (dx - 8) * (initWidth - 4 - (sourcePath[i][1] - (initX + 2))) / (initWidth - 4) + 4;
              }
              else{
                newX = sourcePath[i][1] + dx * (initWidth - 4 - (sourcePath[i][1] - (initX + 2))) / (initWidth - 4);
              }
              newPathW.push([sourcePath[i][0], newX, sourcePath[i][2]]);
            }
          }
          currentObj.attr("path", newPathW);
          break;
        case "text":
          if (dx > initWidth){
            let transformStr = resizeRect.matrix.toTransformString() + "s" + (- resizeRect.attr("width") / initWidth) + ",1," + (resizeRect.attr("x")) + "," + (resizeRect.attr("y")) + currentObj.data("scaleStr");
            currentObj.transform(transformStr);
            resizeRect.data("scaleX", (- resizeRect.attr("width") / initWidth));
            resizeRect.data("scaleY", 1);
            resizeRect.data("scaleCX", resizeRect.attr("x"));
            resizeRect.data("scaleCY", resizeRect.attr("y"));
          }
          else{
            let transformStr = resizeRect.matrix.toTransformString() + "s" + (resizeRect.attr("width") / initWidth) + ",1," + (resizeRect.attr("x") + resizeRect.attr("width")) + "," + (resizeRect.attr("y")) + currentObj.data("scaleStr");
            currentObj.transform(transformStr);
            resizeRect.data("scaleX", (resizeRect.attr("width") / initWidth));
            resizeRect.data("scaleY", 1);
            resizeRect.data("scaleCX", resizeRect.attr("x") + resizeRect.attr("width"));
            resizeRect.data("scaleCY", resizeRect.attr("y"));
          }
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          break;
      }
      break;
    case "ne":
      if (-dx > initWidth / 2){
        resizeRect.attr("x", initX + initWidth + dx);
        resizeRect.attr("width", 2 * (-dx) - initWidth);
      }
      else{
        resizeRect.attr("x", initX - dx);
        resizeRect.attr("width", initWidth + 2 * dx);
      }
      if (dy > initHeight / 2){
        resizeRect.attr("y", initY + initHeight - dy);
        resizeRect.attr("height", 2 * dy - initHeight);
      }
      else{
        resizeRect.attr("y", initY + dy);
        resizeRect.attr("height", initHeight - 2 * dy);
      }
      switch(currentObj.type){
        case "rect":
        case "image":
          currentObj.attr("x", resizeRect.attr("x") + 2);
          currentObj.attr("width", resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4);
          currentObj.attr("y", resizeRect.attr("y") + 2);
          currentObj.attr("height", resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4);
          break;
        case "ellipse":
          currentObj.attr("cx", resizeRect.attr("x") + 2 + (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("rx", (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("cy", resizeRect.attr("y") + 2 + (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          currentObj.attr("ry", (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          break;
        case "path":
          let newPathNE = [];
          if (currentPath){
            newPathNE = currentPath;
          }
          else{
            for (let i = 0; i < sourcePath.length; i++){
              let newX = initWidth != 4 ? sourcePath[i][1] +  2 * dx * (sourcePath[i][1] - (initX + initWidth / 2)) / (initWidth - 4) : sourcePath[i][1];
              let newY = initHeight != 4 ? sourcePath[i][2] - 2 * dy * (sourcePath[i][2] - (initY + initHeight / 2)) / (initHeight - 4) : sourcePath[i][2];
              newPathNE.push([sourcePath[i][0], newX, newY]);
            }
          }
          currentObj.attr("path", newPathNE);
          break;
        case "text":
          let scaleX = 1;
          let scaleY = 1;
          if (-dx > initWidth / 2){
            scaleX = - resizeRect.attr("width") / initWidth;
          }
          else{
            scaleX = resizeRect.attr("width") / initWidth;
          }
          if (dy > initHeight / 2){
            scaleY = - resizeRect.attr("height") / initHeight;
          }
          else{
            scaleY = resizeRect.attr("height") / initHeight;
          }
          let transformStr = resizeRect.matrix.toTransformString() + "s" + scaleX + "," + scaleY + "," + objCenterX + "," + objCenterY + currentObj.data("scaleStr");
          currentObj.transform(transformStr);
          resizeRect.data("scaleX", scaleX);
          resizeRect.data("scaleY", scaleY);
          resizeRect.data("scaleCX", objCenterX);
          resizeRect.data("scaleCY", objCenterY);
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          break;
      }
      break;
    case "se":
      if (-dx > initWidth / 2){
        resizeRect.attr("x", initX + initWidth + dx);
        resizeRect.attr("width", 2 * (-dx) - initWidth);
      }
      else{
        resizeRect.attr("x", initX - dx);
        resizeRect.attr("width", initWidth + 2 * dx);
      }
      if (-dy > initHeight / 2){
        resizeRect.attr("y", initY + initHeight + dy);
        resizeRect.attr("height", - 2 * dy - initHeight);
      }
      else{
        resizeRect.attr("y", initY - dy);
        resizeRect.attr("height", initHeight + 2 * dy);
      }
      switch(currentObj.type){
        case "rect":
        case "image":
          currentObj.attr("x", resizeRect.attr("x") + 2);
          currentObj.attr("width", resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4);
          currentObj.attr("y", resizeRect.attr("y") + 2);
          currentObj.attr("height", resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4);
          break;
        case "ellipse":
          currentObj.attr("cx", resizeRect.attr("x") + 2 + (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("rx", (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("cy", resizeRect.attr("y") + 2 + (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          currentObj.attr("ry", (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          break;
        case "path":
          let newPathSE = [];
          if (currentPath){
            newPathSE = currentPath;
          }
          else{
            for (let i = 0; i < sourcePath.length; i++){
              let newX = initWidth != 4 ? sourcePath[i][1] +  2 * dx * (sourcePath[i][1] - (initX + initWidth / 2)) / (initWidth - 4) : sourcePath[i][1];
              let newY = initHeight != 4 ? sourcePath[i][2] + 2 * dy * (sourcePath[i][2] - (initY + initHeight / 2)) / (initHeight - 4) : sourcePath[i][2];
              newPathSE.push([sourcePath[i][0], newX, newY]);
            }
          }
          currentObj.attr("path", newPathSE);
          break;
        case "text":
          let scaleX = 1;
          let scaleY = 1;
          if (-dx > initWidth / 2){
            scaleX = - resizeRect.attr("width") / initWidth;
          }
          else{
            scaleX = resizeRect.attr("width") / initWidth;
          }
          if (-dy > initHeight / 2){
            scaleY = - resizeRect.attr("height") / initHeight;
          }
          else{
            scaleY = resizeRect.attr("height") / initHeight;
          }
          let transformStr = resizeRect.matrix.toTransformString() + "s" + scaleX + "," + scaleY + "," + objCenterX + "," + objCenterY + currentObj.data("scaleStr");
          currentObj.transform(transformStr);
          resizeRect.data("scaleX", scaleX);
          resizeRect.data("scaleY", scaleY);
          resizeRect.data("scaleCX", objCenterX);
          resizeRect.data("scaleCY", objCenterY);
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          break;
      }
      break;
    case "sw":
      if (dx > initWidth / 2){
        resizeRect.attr("x", initX + initWidth - dx);
        resizeRect.attr("width", 2 * dx - initWidth);
      }
      else{
        resizeRect.attr("x", initX + dx);
        resizeRect.attr("width", initWidth - 2 * dx);
      }
      if (-dy > initHeight / 2){
        resizeRect.attr("y", initY + initHeight + dy);
        resizeRect.attr("height", - 2 * dy - initHeight);
      }
      else{
        resizeRect.attr("y", initY - dy);
        resizeRect.attr("height", initHeight + 2 * dy);
      }
      switch(currentObj.type){
        case "rect":
        case "image":
          currentObj.attr("x", resizeRect.attr("x") + 2);
          currentObj.attr("width", resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4);
          currentObj.attr("y", resizeRect.attr("y") + 2);
          currentObj.attr("height", resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4);
          break;
        case "ellipse":
          currentObj.attr("cx", resizeRect.attr("x") + 2 + (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("rx", (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("cy", resizeRect.attr("y") + 2 + (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          currentObj.attr("ry", (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          break;
        case "path":
          let newPathSW = [];
          if (currentPath){
            newPathSW = currentPath;
          }
          else{
            for (let i = 0; i < sourcePath.length; i++){
              let newX = initWidth != 4 ? sourcePath[i][1] - 2 * dx * (sourcePath[i][1] - (initX + initWidth / 2)) / (initWidth - 4) : sourcePath[i][1];
              let newY = initHeight != 4 ? sourcePath[i][2] + 2 * dy * (sourcePath[i][2] - (initY + initHeight / 2)) / (initHeight - 4) : sourcePath[i][2];
              newPathSW.push([sourcePath[i][0], newX, newY]);
            }
          }
          currentObj.attr("path", newPathSW);
          break;
        case "text":
          let scaleX = 1;
          let scaleY = 1;
          if (dx > initWidth / 2){
            scaleX = - resizeRect.attr("width") / initWidth;
          }
          else{
            scaleX = resizeRect.attr("width") / initWidth;
          }
          if (-dy > initHeight / 2){
            scaleY = - resizeRect.attr("height") / initHeight;
          }
          else{
            scaleY = resizeRect.attr("height") / initHeight;
          }
          let transformStr = resizeRect.matrix.toTransformString() + "s" + scaleX + "," + scaleY + "," + objCenterX + "," + objCenterY + currentObj.data("scaleStr");
          currentObj.transform(transformStr);
          resizeRect.data("scaleX", scaleX);
          resizeRect.data("scaleY", scaleY);
          resizeRect.data("scaleCX", objCenterX);
          resizeRect.data("scaleCY", objCenterY);
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          break;
      }
      break;
    case "nw":
      if (dx > initWidth / 2){
        resizeRect.attr("x", initX + initWidth - dx);
        resizeRect.attr("width", 2 * dx - initWidth);
      }
      else{
        resizeRect.attr("x", initX + dx);
        resizeRect.attr("width", initWidth - 2 * dx);
      }
      if (dy > initHeight / 2){
        resizeRect.attr("y", initY + initHeight - dy);
        resizeRect.attr("height", 2 * dy - initHeight);
      }
      else{
        resizeRect.attr("y", initY + dy);
        resizeRect.attr("height", initHeight - 2 * dy);
      }
      switch(currentObj.type){
        case "rect":
        case "image":
          currentObj.attr("x", resizeRect.attr("x") + 2);
          currentObj.attr("width", resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4);
          currentObj.attr("y", resizeRect.attr("y") + 2);
          currentObj.attr("height", resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4);
          break;
        case "ellipse":
          currentObj.attr("cx", resizeRect.attr("x") + 2 + (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("rx", (resizeRect.attr("width") < 4 ? 0 : resizeRect.attr("width") - 4) / 2);
          currentObj.attr("cy", resizeRect.attr("y") + 2 + (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          currentObj.attr("ry", (resizeRect.attr("height") < 4 ? 0 : resizeRect.attr("height") - 4) / 2);
          break;
        case "path":
          let newPathNW = [];
          if (currentPath){
            newPathNW = currentPath;
          }
          else{
            for (let i = 0; i < sourcePath.length; i++){
              let newX = initWidth != 4 ? sourcePath[i][1] - 2 * dx * (sourcePath[i][1] - (initX + initWidth / 2)) / (initWidth - 4) : sourcePath[i][1];
              let newY = initHeight != 4 ? sourcePath[i][2] - 2 * dy * (sourcePath[i][2] - (initY + initHeight / 2)) / (initHeight - 4) : sourcePath[i][2];
              newPathNW.push([sourcePath[i][0], newX, newY]);
            }
          }
          currentObj.attr("path", newPathNW);
          break;
        case "text":
          let scaleX = 1;
          let scaleY = 1;
          if (dx > initWidth / 2){
            scaleX = - resizeRect.attr("width") / initWidth;
          }
          else{
            scaleX = resizeRect.attr("width") / initWidth;
          }
          if (dy > initHeight / 2){
            scaleY = - resizeRect.attr("height") / initHeight;
          }
          else{
            scaleY = resizeRect.attr("height") / initHeight;
          }
          let transformStr = resizeRect.matrix.toTransformString() + "s" + scaleX + "," + scaleY + "," + objCenterX + "," + objCenterY + currentObj.data("scaleStr");
          currentObj.transform(transformStr);
          resizeRect.data("scaleX", scaleX);
          resizeRect.data("scaleY", scaleY);
          resizeRect.data("scaleCX", objCenterX);
          resizeRect.data("scaleCY", objCenterY);
          currentObj.data("resizeRectX", resizeRect.attr("x"));
          currentObj.data("resizeRectY", resizeRect.attr("y"));
          currentObj.data("resizeRectWidth", resizeRect.attr("width"));
          currentObj.data("resizeRectHeight", resizeRect.attr("height"));
          currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
          break;
      }
      break;
  }
}

/*
  * 计算缩放步长
  * params:缩放按钮,x方向步长,y方向步长
*/
function calcStep(direction, dx, dy){
  let newx = dx, newy = dy;
  if (currentObj.data("rotate") > 22.5 && currentObj.data("rotate") <= 67.5){
    let dxy = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
    switch (direction){
      case "n":
      case "s":
        newy = dy < 0 ? -dxy : dxy;
      break;
      case "e":
      case "w":
        newx = dx < 0 ? -dxy : dxy;
      break;
      case "ne":
      case "sw":
        newx = dx < 0 ? -Math.sqrt(2 * Math.pow(dx, 2)) : Math.sqrt(2 * Math.pow(dx, 2));
        newy = -newx;
      break;
      case "se":
      case "nw":
        newx = dy < 0 ? -Math.sqrt(2 * Math.pow(dy, 2)) : Math.sqrt(2 * Math.pow(dy, 2));
        newy = newx;
      break;
    }
  }
  else if (currentObj.data("rotate") > 67.5 && currentObj.data("rotate") <= 112.5){
    newx = dy;
    newy = -dx;
  }
  else if (currentObj.data("rotate") > 112.5 && currentObj.data("rotate") <= 157.5){
    let dxy = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
    switch (direction){
      case "n":
      case "s":
        newy = dy < 0 ? dxy : -dxy;
      break;
      case "e":
      case "w":
        newx = dx < 0 ? dxy : -dxy;
      break;
      case "ne":
      case "sw":
        newx = dy < 0 ? -Math.sqrt(2 * Math.pow(dy, 2)) : Math.sqrt(2 * Math.pow(dy, 2));
        newy = -newx;
      break;
      case "se":
      case "nw":
        newx = dx < 0 ? Math.sqrt(2 * Math.pow(dx, 2)) : -Math.sqrt(2 * Math.pow(dx, 2));
        newy = newx;
      break;
    }
  }
  else if (currentObj.data("rotate") > 157.5 || currentObj.data("rotate") <= -157.5){
    newx = -dx;
    newy = -dy;
  }
  else if (currentObj.data("rotate") > -157.5 && currentObj.data("rotate") <= -112.5){
    let dxy = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
    switch (direction){
      case "n":
      case "s":
        newy = dy < 0 ? dxy : -dxy;
      break;
      case "e":
      case "w":
        newx = dx < 0 ? dxy : -dxy;
      break;
      case "ne":
      case "sw":
        newx = dx < 0 ? Math.sqrt(2 * Math.pow(dx, 2)) : -Math.sqrt(2 * Math.pow(dx, 2));
        newy = -newx;
      break;
      case "se":
      case "nw":
        newx = dy < 0 ? Math.sqrt(2 * Math.pow(dy, 2)) : -Math.sqrt(2 * Math.pow(dy, 2));
        newy = newx;
      break;
    }
  }
  else if (currentObj.data("rotate") > -112.5 && currentObj.data("rotate") <= -67.5){
    newx = -dy;
    newy = dx;
  }
  else if (currentObj.data("rotate") > -67.5 && currentObj.data("rotate") <= -22.5){
    let dxy = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
    switch (direction){
      case "n":
      case "s":
        newy = dy < 0 ? -dxy : dxy;
      break;
      case "e":
      case "w":
        newx = dx < 0 ? -dxy : dxy;
      break;
      case "ne":
      case "sw":
        newx = dy < 0 ? Math.sqrt(2 * Math.pow(dy, 2)) : -Math.sqrt(2 * Math.pow(dy, 2));
        newy = -newx;
      break;
      case "se":
      case "nw":
        newx = dx < 0 ? -Math.sqrt(2 * Math.pow(dx, 2)) : Math.sqrt(2 * Math.pow(dx, 2));
        newy = newx;
      break;
    }
  }
  return { dx: newx, dy: newy };
}

/*
  * 定义旋转按钮
  * params:画布
*/
function drawRotateRect(paper){
  let rotate = paper.rect(0, 0, 32, 32)
    .drag(rotateMove, rotateStartMove, rotateEndMove)
    .hover(function(){
      rotate.attr('cursor', "url(/images/rotate.svg) 8 8,default");
    }, function(){})
    .attr({ "stroke-width": 0, fill:"#fff", "fill-opacity": 0});

  let rotateX = 0;
  let rotateY = 0;
  let startAngle = 0;

  function rotateStartMove(x, y){
    diagram.removeEventListener("mouseover", diagramMouseOver);
    diagram.removeEventListener("mousedown", diagramMouseDown);
    diagram.removeEventListener("mousemove", diagramMouseMove);
    diagram.removeEventListener("mouseup", diagramMouseUp);
    objCenterX = currentObj.getBBox().x + currentObj.getBBox().width / 2 ;
    objCenterY = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    rotateX = x;
    rotateY = y;
    this.angle = 0;
    this.tempangle = 0;
    startAngle = currentObj.data("rotate");
  }

  let ddx = 0; // 旋转结束后的角度
  function rotateMove(dx, dy, x, y){
    let angle = (Math.atan2((y - objCenterY), (x - objCenterX)) - Math.atan2((rotateY - objCenterY), (rotateX - objCenterX))) * 180 / Math.PI;
    //resizeRect = resizeRect.transform("r" + (currentObj.data("rotate") ? currentObj.data("rotate") + angle : angle) + "," + objCenterX + "," + objCenterY);
    resizeRect.rotate(angle - this.tempangle)
    if (currentObj.type == "text"){
      let transformStr = resizeRect.matrix.toTransformString() + currentObj.data("scaleStr");
      currentObj = currentObj.transform(transformStr);
    }
    else{
      currentObj.rotate(angle - this.tempangle)
      //currentObj = currentObj.transform("r" + (currentObj.data("rotate") ? currentObj.data("rotate") + angle : angle) + "," + objCenterX + "," + objCenterY);
    }
    setResizeBtnLocation(currentObj.data("rotate") ? currentObj.data("rotate") + angle : angle);
    this.tempangle = angle;
    this.angle = currentObj.data("rotate") ? currentObj.data("rotate") + angle : angle;
    diagram.style.cursor = "url(/images/rotate.svg) 8 8,default";
    if (this.angle >= 180){
      this.angle = this.angle - 360;
    }
    if (this.angle <= -180){
      this.angle = this.angle + 360;
    }
    propertyForm.rotate = this.angle;
  }

  function rotateEndMove(e){
    this.tempangle = 0;
    currentObj.data("rotate", this.angle);
    currentObj.data("resizeRectTransform", resizeRect.matrix.toTransformString());
    diagram.addEventListener("mouseover", diagramMouseOver);
    diagram.addEventListener("mousedown", diagramMouseDown);
    diagram.addEventListener("mousemove", diagramMouseMove);
    diagram.addEventListener("mouseup", diagramMouseUp);
    objCenterX = currentObj.getBBox().x + currentObj.getBBox().width / 2 ;
    objCenterY = currentObj.getBBox().y + currentObj.getBBox().height / 2;
    diagram.style.cursor = 'default';
    undos.push({ command: "RotateObjectCommand", obj: currentObj, oldValue: startAngle, value: this.angle });
  }
  rotate.hide();
  return rotate;
}

/*
  * 获取形变按钮位置
  * params:形变框
*/
function getTransformedPoints(rect) {
  const matrix = rect.matrix;
  const points = [
    { x: rect.attr("x"), y: rect.attr("y") },       // 左上角原始坐标
    { x: rect.attr("x") + rect.attr("width"), y: rect.attr("y") },     // 右上角原始坐标
    { x: rect.attr("x") + rect.attr("width"), y: rect.attr("y") + rect.attr("height") },   // 右下角原始坐标
    { x: rect.attr("x"), y: rect.attr("y") + rect.attr("height") }      // 左下角原始坐标
  ];
  const transformedPoints = points.map(point => {
    const x = matrix.a * point.x + matrix.c * point.y + matrix.e;
    const y = matrix.b * point.x + matrix.d * point.y + matrix.f;
    return { x, y };
  });
  return transformedPoints;
}

/*
  * 设置形变按钮位置
  * params:旋转角度
*/
function setResizeBtnLocation(angle){
  let points = getTransformedPoints(resizeRect);
  let resizebtnSize = 4;

  let nTransformStr = "t" + ((points[1].x + points[0].x) / 2 - resizebtnSize).toString() 
    + "," + ((points[1].y + points[0].y) / 2 - resizebtnSize).toString()
    + "r" + (angle ? angle : 0).toString();
  nResize.transform(nTransformStr);
  nResize.show();

  let eTransformStr = "t" + ((points[2].x + points[1].x) / 2 - resizebtnSize).toString() 
    + "," + ((points[2].y + points[1].y) / 2 - resizebtnSize).toString()
    + "r" + (angle ? angle : 0).toString();
  eResize.transform(eTransformStr);
  eResize.show();

  let sTransformStr = "t" + ((points[3].x + points[2].x) / 2 - resizebtnSize).toString() 
    + "," + ((points[3].y + points[2].y) / 2 - resizebtnSize).toString()
    + "r" + (angle ? angle : 0).toString();
  sResize.transform(sTransformStr);
  sResize.show();

  let wTransformStr = "t" + ((points[0].x + points[3].x) / 2 - resizebtnSize).toString() 
    + "," + ((points[0].y + points[3].y) / 2 - resizebtnSize).toString()
    + "r" + (angle ? angle : 0).toString();
  wResize.transform(wTransformStr);
  wResize.show();

  let nwTransformStr = "t" + (points[0].x - resizebtnSize).toString() + "," + (points[0].y - resizebtnSize).toString()
    + "r" + (angle ? angle : 0).toString();
  nwResize.transform(nwTransformStr);
  nwResize.show();

  let neTransformStr = "t" + (points[1].x - resizebtnSize).toString() + "," + (points[1].y - resizebtnSize).toString()
    + "r" + (angle ? angle : 0).toString();
  neResize.transform(neTransformStr);
  neResize.show();

  let seTransformStr = "t" + (points[2].x - resizebtnSize).toString() + "," + (points[2].y - resizebtnSize).toString()
    + "r" + (angle ? angle : 0).toString();
  seResize.transform(seTransformStr);
  seResize.show();

  let swTransformStr = "t" + (points[3].x - resizebtnSize).toString() + "," + (points[3].y - resizebtnSize).toString()
    + "r" + (angle ? angle : 0).toString();
  swResize.transform(swTransformStr);
  swResize.show();

  let rotateBtnSize = 16;
  let nwRotateTransformStr = "t" + (points[0].x - rotateBtnSize).toString() 
    + "," + (points[0].y - rotateBtnSize).toString();
  nwRotateRect.transform(nwRotateTransformStr);
  nwRotateRect.show();

  let neRotateTransformStr = "t" + (points[1].x - rotateBtnSize).toString() 
    + "," + (points[1].y - rotateBtnSize).toString();
  neRotateRect.transform(neRotateTransformStr);
  neRotateRect.show();

  let seRotateTransformStr = "t" + (points[2].x - rotateBtnSize).toString() 
    + "," + (points[2].y - rotateBtnSize).toString();
  seRotateRect.transform(seRotateTransformStr);
  seRotateRect.show();

  let swRotateTransformStr = "t" + (points[3].x - rotateBtnSize).toString() 
    + "," + (points[3].y - rotateBtnSize).toString();
  swRotateRect.transform(swRotateTransformStr);
  swRotateRect.show();
}

/*
  * 删除元素
*/
function deleteObj(){
  if (currentObj){
    let obj = currentObj;
    obj.hide();
    currentObj = null;
    resizeRect.hide();
    resizeSet.hide();
    inputBox.blur();
    // 光标隐藏
    textCursor.hide();
    textCursor.data("status", "hide");
    if (textCursorInterval){
      clearInterval(textCursorInterval);
      textCursorInterval = undefined;
    }
    undos.push({ command: "DeleteObjectCommand", obj: obj });
  }
}

/*
  * 清空画布
*/
function clear(){
  ElMessageBox.confirm("清空后无法复原，确认清空画布?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(
    () => {
      for(let i = 0; i < mainArr.length; i++){
        let elem = mainArr[i];
        elem.remove();
      }
      mainArr = [];
      mainSet = paper.set();
      currentObj = null;
      resizeRect.hide();
      resizeSet.hide();
      inputBox.blur();
      // 光标隐藏
      textCursor.hide();
      textCursor.data("status", "hide");
      if (textCursorInterval){
        clearInterval(textCursorInterval);
        textCursorInterval = undefined;
      }
      // 设置属性值
      setProperty();
    },
    () => {
    }
  );
}

/*
  * 置底
*/
function toBack(){ 
  if (currentObj){
    currentObj.toBack();
    mainArr = mainArr.filter(item => item != currentObj);
    mainArr.push(currentObj);
  }
}

/*
  * 置顶
*/
function toFront(){ 
  if (currentObj){
    currentObj.toFront();
    mainArr = mainArr.filter(item => item != currentObj);
    mainArr.unshift(currentObj);
  }
}

/*
  * 导入图片
*/
function importImg(){ 
  document.getElementById('imageInput').click();
}

/*
  * 导出png图片
*/
function exportPng(){ 
  currentObj = null;
  resizeRect.hide();
  resizeSet.hide();
  inputBox.blur();
  // 光标隐藏
  textCursor.hide();
  textCursor.data("status", "hide");
  if (textCursorInterval){
    clearInterval(textCursorInterval);
    textCursorInterval = undefined;
  }
  // 设置属性值
  setProperty();
  let svgElement = document.getElementById('paper');
  svgToImage(svgElement, svgElement.clientWidth, svgElement.clientHeight, function(dataURL){
    // 此处的dataURL就是转换后的图片的DataURL
    // 你可以使用这个dataURL做进一步的操作，比如下载或者显示图片
    var a = document.createElement('a');
    a.href = dataURL;
    a.download = 'image.png';
    a.click();
  })
}

/*
  * svg转图片
*/
function svgToImage(svgElement, width, height, callback) {
    // 创建一个Canvas对象
    var canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    // 绘制Canvas
    var ctx = canvas.getContext('2d');
    var data = (new XMLSerializer()).serializeToString(svgElement);
    var DOMURL = window.URL || window.webkitURL || window;
    var img = new Image();
    var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
    var url = DOMURL.createObjectURL(svgBlob);
 
    img.onload = function() {
        ctx.drawImage(img, 0, 0);
        DOMURL.revokeObjectURL(url);
        callback(canvas.toDataURL('image/png')); // 输出图片的DataURL
    };
 
    img.src = url;
}

/*
  * 导出svg
*/
function exportSvg(){ 
  currentObj = null;
  resizeRect.hide();
  resizeSet.hide();
  inputBox.blur();
  // 光标隐藏
  textCursor.hide();
  textCursor.data("status", "hide");
  if (textCursorInterval){
    clearInterval(textCursorInterval);
    textCursorInterval = undefined;
  }
  // 设置属性值
  setProperty();
  // 创建Blob对象
  var serializer = new XMLSerializer();
  var svgString = serializer.serializeToString(paper.canvas);
  var blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
  var url = URL.createObjectURL(blob);
  
  // 创建下载链接
  var a = document.createElement('a');
  a.href = url;
  a.download = 'canvas.svg';
  a.click();
}
</script>

<style>
.main-div {
    width: calc(100vw - 320px);
    float: left;
    height: 100%;
  }
  .diagram-div {
    width: 100%;
    height: calc(100vh - 65px);
  }
  .property {
    width: 250px;
    background-color: #545c64;
    float: left;
    height: 100%;
    color: white;
  }
  .el-form-item__label{
    color: white;
  }
  .slide {
    width: 24px;
    height: 24px;
    position: absolute;
    top: 300px;
    right: 20px;
  }
  .slide-btn {
    width: 24px;
    height: 24px;
  }
  .btnDiv {
    position: absolute;
    top: 10px;
    left: 200px;
  }
  .image-select .image {
    width: 32px;
    height: 32px;
    display: block;
  }
  .image-select .el-upload {
    border: 1px dashed var(--el-border-color);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
  }
  
  .image-select .el-upload:hover {
    border-color: var(--el-color-primary);
  }
  
  .el-icon.image-select-icon {
    font-size: 28px;
    color: #8c939d;
    width: 32px;
    height: 32px;
    text-align: center;
  }
  .el-menu-item * {
    vertical-align: middle;
}
</style>
